-
Notifications
You must be signed in to change notification settings - Fork 559
[TOOL-4827] Move Nebula out of dashboard #7356
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
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
WalkthroughThis change removes all Nebula AI chat integration and related components from the dashboard app and migrates Nebula into its own standalone app under Changes
Sequence Diagram(s)Not applicable: The changes are architectural and involve large-scale migration and removal/addition of features, not a single control flow or new feature. Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNone found. Possibly related PRs
Suggested labels
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
size-limit report 📦
|
3cfea8b
to
d8ca728
Compare
d8ca728
to
621e452
Compare
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.
Actionable comments posted: 50
🔭 Outside diff range comments (12)
apps/nebula/src/@/constants/local-node.ts (1)
1-7
: Avoid hardcoding private keys
Embedding a private key—even for local testnets—poses a security risk and may be flagged by static analysis (e.g., Gitleaks). Move this value to a.env
or secure vault and document that it's only for non-production use.apps/nebula/src/app/login/page.tsx (1)
5-13
:searchParams
should not be typed/treated as aPromise
searchParams
is synchronously provided by Next.js; wrapping it in aPromise
and thenawait
-ing introduces needless complexity and type-mismatch risk.-export default async function NebulaLogin(props: { - searchParams: Promise<{ +export default async function NebulaLogin(props: { + searchParams: { chain?: string | string[]; q?: string | string[]; - }>; + }; }) { - const searchParams = await props.searchParams; + const { searchParams } = props;apps/nebula/src/@/utils/authToken.ts (2)
7-10
:cookies()
is synchronous –await
here adds needless latency and forces these helpers to beasync
next/headers
returns a synchronousRequestCookies
instance. The extraawait
:
- Marks both helpers as
async
, creating an unnecessary promise wrapper.- Hides accidental misuse from the client side – the compiler won’t warn because the function is already
async
.-export async function getNebulaAuthToken() { - const cookiesManager = await cookies(); +export function getNebulaAuthToken() { + const cookiesManager = cookies(); const activeAccount = cookiesManager.get(NEBULA_COOKIE_ACTIVE_ACCOUNT)?.value;Apply the same change in
getNebulaAuthTokenWalletAddress
.
17-20
: Duplicate async-await issue in second helperSame reasoning as above – drop
await
and theasync
keyword.apps/nebula/src/app/(app)/chat/[session_id]/page.tsx (1)
11-18
:params
should not be typed asPromise<...>
In a Next.js server component
Page
function,props.params
is already a plain object, not a promise.
Typing it asPromise<{ session_id: string }>
forces consumers toawait
something that is neverthen
-able and will break type-checking.-export default async function Page(props: { - params: Promise<{ - session_id: string; - }>; -}) { - const params = await props.params; +export default async function Page(props: { + params: { + session_id: string; + }; +}) { + const params = props.params;apps/nebula/src/app/(app)/components/Chats.tsx (2)
124-146
: Avoid using array index as React key
key={index}
risks incorrect reconciliation when messages are inserted/removed, breaking scroll-position logic and causing animation glitches.
Prefer a stable identifier such asrequest_id
or an incrementingid
generated on the server.- key={index} + key={message.request_id ?? index}
88-110
: Missing cleanup for dynamically-attached scroll listeners
mousedown
/wheel
handlers are added every timeenableAutoScroll
turnstrue
, but they’re only removed inside the handler.
If the component unmounts before the user scrolls, listeners leak, keeping the DOM node in memory.Add an explicit cleanup in the
useEffect
return value:chatScrollContainer.addEventListener("mousedown", disableScroll); chatScrollContainer.addEventListener("wheel", disableScroll); + + return () => { + chatScrollContainer.removeEventListener("mousedown", disableScroll); + chatScrollContainer.removeEventListener("wheel", disableScroll); + }; }, [setEnableAutoScroll, enableAutoScroll]);apps/nebula/src/app/login/auth-actions.ts (1)
77-80
:cookies()
is synchronous – remove unnecessaryawait
cookies()
fromnext/headers
returns aRequestCookies
object, not a Promise.
Usingawait
compiles but yieldsunknown
and loses type safety.- const cookieStore = await cookies(); + const cookieStore = cookies();Apply the same change at lines 173 and 186.
This prevents accidentalany
leakage and avoids needless micro-tasks.Also applies to: 172-189
apps/nebula/src/app/(app)/components/ChatPageContent.tsx (1)
451-469
: Race-condition can leaverequest_id
empty on earlydelta
events
requestIdForMessage
is populated only after the"init"
event yet is relied upon for every"delta"
payload that follows.
If the backend ever streams adelta
beforeinit
(not guaranteed by many SSE / WebSocket back-ends), the first assistant message(s) will be created with an emptyrequest_id
, making later reconciliation impossible.- case "delta": { + case "delta": { + // ensure we have the request-id even if INIT arrived late + if (!requestIdForMessage && res.request_id) { + requestIdForMessage = res.request_id; + }Alternatively, buffer deltas until the
init
frame appears.apps/nebula/src/@/components/blocks/client-only.tsx (1)
31-36
: Avoid emittingundefinedms
whenfadeInDuration
is omitted
${fadeInDuration}ms
yields"undefinedms"
if the caller does not provide the prop, resulting in an invalid CSS value. Replace with a conditional spread.- style={{ - animationDuration: `${fadeInDuration}ms`, - opacity: fadeInDuration ? 0 : 1, - ...style, - }} + style={{ + ...(fadeInDuration !== undefined && { + animationDuration: `${fadeInDuration}ms`, + opacity: 0, + }), + ...(fadeInDuration === undefined && { opacity: 1 }), + ...style, + }}apps/dashboard/src/components/CustomChat/CustomChatContent.tsx (2)
16-24
: Remove unusednetworks
prop to prevent dead code & misleading API
networks
is accepted byCustomChatContent
but isn’t used or forwarded
anymore. Leaving it around encourages accidental reliance on a value that
does nothing.- networks: NebulaContext["networks"];
Also drop the corresponding import of
NebulaContext
on line 14.
105-116
: Guard against missingNEXT_PUBLIC_SIWA_URL
If the env var is undefined the fetch URL becomes
"undefined/v1/chat"
,
causing an opaque network error that is hard to trace.-const apiUrl = process.env.NEXT_PUBLIC_SIWA_URL; +const apiUrl = process.env.NEXT_PUBLIC_SIWA_URL; +if (!apiUrl) { + throw new Error("Missing NEXT_PUBLIC_SIWA_URL env var"); +}
♻️ Duplicate comments (3)
apps/nebula/src/app/(app)/components/Chatbar.stories.tsx (1)
1-1
: Same alias concern applies here.
See earlier comment on@/storybook/utils
.apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx (1)
1-1
: Alias configuration reuse.
Same verification needed for@/storybook/stubs
.apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx (1)
1-1
: Alias configuration reuse.
Same verification needed for@/storybook/utils
.
🧹 Nitpick comments (108)
apps/nebula/README.md (2)
1-1
: Add a trailing newline
POSIX conventions and many tools expect files to end with a newline.Apply this diff:
--- a/apps/nebula/README.md +++ b/apps/nebula/README.md @@ -1 +1,2 @@ # nebula.thirdweb.com +
1-1
: Expand README with project details
This one-line README lacks context—consider adding sections for Overview, Setup, Development, Configuration, and links to related docs to improve onboarding and maintainability.apps/nebula/knip.json (1)
2-2
: Pin$schema
to a fixed version for stability.Using a floating unpkg URL can introduce breaking changes when
knip
releases a new major version. Consider specifying an exact version (e.g.,"https://unpkg.com/knip@5.11.0/schema.json"
).apps/nebula/src/app/not-found.tsx (1)
25-27
: Minor a11y / semantics improvement for the homepage linkConsider adding an explicit
aria-label
(or clearer link text) so screen-reader users understand the destination without surrounding context.- <Link href="/" className="text-foreground hover:underline"> - homepage + <Link + href="/" + aria-label="Go to Nebula homepage" + className="text-foreground hover:underline" + > + homepage </Link>apps/nebula/.env.example (1)
1-2
: Remove unnecessary quote characters
Dotenv-linter flags quote characters in these values; they can be unquoted for consistency with other examples:-NEXT_PUBLIC_IPFS_GATEWAY_URL="https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path}" -NEXT_PUBLIC_NEBULA_URL="https://nebula-api.thirdweb-dev.com" +NEXT_PUBLIC_IPFS_GATEWAY_URL=https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path} +NEXT_PUBLIC_NEBULA_URL=https://nebula-api.thirdweb-dev.comapps/nebula/src/@/lib/utils.ts (1)
4-6
: Prefer spreadinginputs
when callingclsx
clsx
is variadic – passing the whole array as a single argument works, but the more idiomatic (and marginally faster) way is to spread the inputs so eachClassValue
is handled individually.-export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(...inputs)); }apps/nebula/src/@/data/eth-sanctioned-addresses.ts (1)
139-150
: Switch toSet
for constant-time lookup & smaller memory overheadUsing an object map works, but a
Set<string>
is semantically clearer, avoids accidental prototype collisions, and slightly reduces memory by storing each address only once.-// build map of sanctioned addresses -const SANCTIONED_ADDRESSES_MAP = ETH_SANCTIONED_ADDRESSES.reduce( - (map, address) => { - map[address.toLowerCase()] = true; - return map; - }, - {} as Record<string, boolean>, -); +// build a set of sanctioned addresses (all lowercase) +const SANCTIONED_ADDRESSES_SET = new Set( + ETH_SANCTIONED_ADDRESSES.map((addr) => addr.toLowerCase()), +); -export function isSanctionedAddress(address: string) { - return SANCTIONED_ADDRESSES_MAP[address.toLowerCase()] || false; +export function isSanctionedAddress(address: string) { + return SANCTIONED_ADDRESSES_SET.has(address.toLowerCase()); }apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts (1)
4-21
: Add explicit return type & destructure params for clarityExplicitly declaring the return type makes the API contract obvious and prevents unintended widening. Destructuring the options object improves readability.
-export function resolveSchemeWithErrorHandler(options: { - uri: string | undefined; - client: ThirdwebClient; -}) { - if (!options.uri) { +export function resolveSchemeWithErrorHandler({ + uri, + client, +}: { + uri?: string; + client: ThirdwebClient; +}): string | undefined { + if (!uri) { return undefined; } try { // eslint-disable-next-line no-restricted-syntax - return resolveScheme({ - uri: options.uri, - client: options.client, - }); + return resolveScheme({ uri, client }); } catch (err) { - console.error("error resolving ipfs url", options.uri, err); + console.error("error resolving ipfs url", uri, err); return undefined; } }apps/nebula/LICENSE.md (1)
189-195
: Check that the copyright notice reflects the correct organizationLine 189 attributes copyright to Non-Fungible Labs, Inc..
If Nebula is maintained by a different entity, update the placeholder to avoid licensing ambiguities.apps/nebula/src/@/lib/reactive.ts (2)
37-41
: PreferObject.is
(or a custom comparer) over strict===
for value change detectionUsing
===
rejects updates only when the reference or primitive value is identical, but it still treatsNaN !== NaN
and ignores structural equality for objects/functions.
If callers pass new objects that are deeply equal, unnecessary re-renders occur; conversely,NaN
flips every time.- if (newValue === value) { + // Use Object.is for edge-cases like NaN, or allow an optional + // comparator so callers can plug in deep/structural equality. + if (Object.is(newValue, value)) { return; }
53-55
: Server-side snapshot missing is harmless here but worth documenting
useSyncExternalStore
’s 3rd argument is used during SSR/SSG.
Because this file is declared"use client"
, React will never invoke the server variant, but passing the samegetValue
can look confusing. A one-liner comment avoids future clean-ups.- return useSyncExternalStore(store.subscribe, store.getValue, store.getValue); + // Third arg only used during SSR – identical impl is fine because this module is client-only. + return useSyncExternalStore(store.subscribe, store.getValue, store.getValue);apps/nebula/src/@/components/blocks/Img.tsx (1)
73-84
: Minor: avoid duplicatingstyle
merge logic
style
is merged twice (once on<img>
, again on the overlay). Extract once to
aconst mergedStyle
to keep source of truth single.apps/nebula/.eslintrc.js (1)
51-57
: Consider bumpingecmaVersion
to 2022 for modern syntaxThe codebase already uses optional chaining, nullish coalescing,
??=
, etc.
SettingecmaVersion: 2022
(or"latest"
) prevents ESLint from mis-parsing newer constructs.apps/nebula/src/@/lib/DashboardRouter.tsx (2)
50-55
:startTransition
is omitted from the dependency array – future React releases may flag this.
startTransition
is technically stable today, but the guaranteed-stability contract is not documented. Adding it (or explicitly commenting that the omission is intentional) keeps the code resilient to future React changes and satisfies lint rules without disabling them repo-wide.- // eslint-disable-next-line no-restricted-syntax - useEffect(() => { + useEffect(() => { RouteStartTransitionFn.setValue(startTransition); - }, []); + }, [startTransition]);
75-90
: RecursiveupdateProgressBar
lacks an exit when loading finishes – latent timers keep firing.When the route settles, the effect is re-run and
isMounted
becomes false, but all pending recursiveawait wait(...)
calls still resolve and re-schedule themselves before hitting theisMounted
guard, causing unnecessarysetProgress
churn.
Consider cancelling the loop explicitly whenisRouteLoading
flips to false.- await wait(delay); - // increase progress … - updateProgressBar(progress + (100 - progress) / 10, delay * 1.05); + await wait(delay); + if (!isRouteLoading) return; // hard stop + updateProgressBar(progress + (100 - progress) / 10, delay * 1.05);apps/nebula/src/app/(app)/api/chat.ts (1)
120-148
: Avoid doubleJSON.parse
on the same payload.
event.data
is parsed intodata
, thendata.data
is parsed again inside each branch.
Parsing once and re-using the result is cheaper and removes redundancy.-const data = JSON.parse(event.data); - -if (data.type === "sign_transaction") { - try { - const parsedTxData = JSON.parse(data.data) as NebulaTxData; +const parsedAction = JSON.parse(event.data); + +if (parsedAction.type === "sign_transaction") { + try { + const parsedTxData = JSON.parse(parsedAction.data) as NebulaTxData; ... - request_id: data.request_id, + request_id: parsedAction.request_id,(Same simplification for the
sign_swap
branch.)apps/nebula/src/app/(app)/api/session.ts (1)
80-99
: Error message copy-paste makes debugging harder.
deleteSession
,getSessions
, andgetSessionById
still throw"Failed to update session"
on failure, which is misleading.- if (!res.ok) { - throw new Error("Failed to update session"); + if (!res.ok) { + throw new Error("Failed to delete session"); }(Apply analogous wording to the other two functions.)
apps/nebula/src/app/(app)/chat/history/page.tsx (1)
9-14
: GuardloginRedirect()
with an early-return
IfloginRedirect()
does not internally throw (e.g. it merely does aredirect()
client-side), the code will continue and attempt to hit the sessions API with an invalid token. Add an earlyreturn
(or rely on the thrown redirect) to avoid unnecessary work & log noise.if (!authToken) { loginRedirect(); + return null; }
apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx (1)
11-11
: Prefer path-alias over deep relative importThe five-level relative path quickly becomes brittle as the file moves or further folders are introduced.
Consider switching to the existing alias convention for internal libs:-import { CustomChatButton } from "../../../../../components/CustomChat/CustomChatButton"; +import { CustomChatButton } from "@/components/CustomChat/CustomChatButton";Keeps the import stable and far easier to read.
No functional change – purely a maintainability lift.apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx (1)
20-20
: Prefer alias instead of deep relative pathEvery other dashboard icon import now relies on the
@/…
alias. Keeping one extremely deep relative path (../../../../../../(dashboard)/(chain)/components/server/icons/NebulaIcon
) is brittle and will break on the next directory move.-import { NebulaIcon } from "../../../../../../(dashboard)/(chain)/components/server/icons/NebulaIcon"; +import { NebulaIcon } from "@/app/(app)/(dashboard)/(chain)/components/server/icons/NebulaIcon";(or expose
NebulaIcon
via a top-level alias like@/icons
to match Nebula app).apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx (1)
10-10
: Alias consistency forCustomChatButton
Same consistency point as above—consider replacing the long relative import with an alias to avoid path churn during future directory moves.
-import { CustomChatButton } from "../../../../../../components/CustomChat/CustomChatButton"; +import { CustomChatButton } from "@/components/CustomChat/CustomChatButton";apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts (1)
6-6
: Prefer absolute alias to stay consistent with new import conventionMost files in this PR migrate to
@/icons/NebulaIcon
(or other alias‐based paths). Keeping one relative path sneaks in an implicit exception and will be the first place that breaks if this file moves.-import { NebulaIcon } from "./icons/NebulaIcon"; +import { NebulaIcon } from "@/icons/NebulaIcon";apps/nebula/src/app/(app)/api/types.ts (1)
76-82
: Hex-typedvalue
would improve correctness
value
is ETH in wei and should — likedata
— be prefixed with0x
. Tighten the type to prevent decimal strings slipping through:- value?: string; + value?: `0x${string}`;apps/nebula/src/@/constants/env-utils.ts (1)
1-3
: Fallback toNODE_ENV
to cover non-Vercel deploymentsIf this package is consumed outside Vercel, both
VERCEL_ENV
vars will be undefined even in production. Consider:export const isProd = - (process.env.VERCEL_ENV || process.env.NEXT_PUBLIC_VERCEL_ENV) === - "production"; + (process.env.VERCEL_ENV || + process.env.NEXT_PUBLIC_VERCEL_ENV || + process.env.NODE_ENV) === "production";apps/nebula/src/app/(app)/chat/[session_id]/page.tsx (1)
21-24
: Return after callingloginRedirect
for clarity
loginRedirect
internally callsredirect()
which throws and never returns, but adding an explicitreturn
(or placing the remaining code in anelse
) makes the intent obvious and keeps TypeScript happy if the helper implementation ever changes.apps/nebula/src/app/move-funds/connect-button.tsx (1)
11-12
: Theme fallback may cause UI flash on first render
useTheme()
returnsundefined
during the hydration pass. Passing"dark"
as a fallback (line 41) can result in a light-to-dark flash when the real theme resolves.
Consider delaying theConnectButton
render until the theme is resolved, or use"system"
/undefined
until a value is available.- theme={getSDKTheme(theme === "light" ? "light" : "dark")} + theme={ + theme ? getSDKTheme(theme === "light" ? "light" : "dark") : undefined + }apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx (1)
176-201
: Avoid rebuilding thetokensToShowOnTop
set on every query
tokensToShowOnTop
is recomputed inside thequeryFn
, causing unnecessary allocation and hashing on every refetch.
Move it to module scope or wrap inuseMemo
.- const tokensToShowOnTop = new Set( - [ - // base - ... - ].map((x) => getAddress(x)), - ); +const TOKENS_TO_SHOW_ON_TOP = new Set( + [ + /* base */ "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", + /* … */ + ].map(getAddress), +); ... - return json.data.sort((a, b) => { - if (tokensToShowOnTop.has(getAddress(a.token_address))) { + return json.data.sort((a, b) => { + if (TOKENS_TO_SHOW_ON_TOP.has(getAddress(a.token_address))) {apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx (1)
52-55
: Minor: memoisedefineChain
result
defineChain(txData.chainId)
is pure but recreates a chain object on every render; memoising avoids needless object churn.- const chain = defineChain(txData.chainId); + const chain = useMemo(() => defineChain(txData.chainId), [txData.chainId]); + // remember to import React.useMemoapps/nebula/src/@/storybook/stubs.ts (1)
24-27
: (Nit) Use crypto-safe randomness when mocking isn’t required
Math.random()
is fine for Storybook stubbing, but if the helper ever leaks into production code a crypto-safe or seeded RNG would be preferable for determinism and security. Flagged for consideration only.apps/nebula/src/@/components/ui/inline-code.tsx (1)
3-16
: Exposechildren
instead of a dedicatedcode
propUsing the implicit
children
prop aligns with common React patterns and lets callers embed any JSX (e.g.<InlineCode>{variable}</InlineCode>
).-export function InlineCode({ - code, - className, -}: { code: string; className?: string }) { +export function InlineCode({ + children, + className, +}: { children: React.ReactNode; className?: string }) { return ( <code className={cn( "mx-0.5 inline rounded-lg border border-border bg-muted px-[0.4em] py-[0.25em] font-mono text-[0.85em] text-foreground", className, )} > - {code} + {children} </code> ); }No functional change, purely ergonomic.
apps/nebula/src/@/utils/loginRedirect.ts (1)
3-9
: Clarify unreachable branch & guard empty strings
redirect()
never returns, so the second call is unreachable in practice.
Inlining anelse
makes intent clearer and avoidsencodeURIComponent(undefined)
if an empty string sneaks through.-export function loginRedirect(path?: string): never { - if (!path) { - redirect("/login"); - } - - redirect(`/login?next=${encodeURIComponent(path)}`); +export function loginRedirect(path?: string): never { + if (!path) { + redirect("/login"); + } else { + redirect(`/login?next=${encodeURIComponent(path)}`); + } }Pure readability; no runtime difference under Next.js.
apps/nebula/src/@/components/blocks/auto-connect.tsx (1)
6-15
: Forward additional props for greater composabilityRight now
TWAutoConnect
is a thin wrapper that hard-codes the accepted props. Forwarding...rest
lets consumers opt into new options fromAutoConnect
without touching this wrapper.-export function TWAutoConnect(props: { - accountAbstraction?: SmartWalletOptions; - client: ThirdwebClient; -}) { +export function TWAutoConnect({ + accountAbstraction, + client, + ...rest +}: { + accountAbstraction?: SmartWalletOptions; + client: ThirdwebClient; + [key: string]: unknown; +}) { return ( <AutoConnect - client={props.client} - accountAbstraction={props.accountAbstraction} + client={client} + accountAbstraction={accountAbstraction} + {...rest} /> ); }Non-breaking enhancement for future-proofing.
apps/nebula/src/app/layout.tsx (1)
37-48
: Consider removingsuppressHydrationWarning
unless neededThe flag masks hydration mismatches that often signal real bugs. If no client-side rendered markup intentionally diverges from SSR output, dropping the attribute tightens correctness.
apps/nebula/components.json (1)
6-12
: Double-check relative paths intailwind
section
"config": "tailwind.config.js"
and"css": "src/global.css"
are interpreted relative to the current working directory of the shadcn UI CLI (usually the project root).
Because this file lives inapps/nebula/
, the paths may resolve incorrectly when running generators from that folder.If generation fails, prepend
./
or use workspace-relative paths:- "config": "tailwind.config.js", - "css": "src/global.css", + "config": "./tailwind.config.js", + "css": "./src/global.css",apps/nebula/src/app/login/auth-actions.ts (1)
90-124
: Harden error handling around failed login
fetch
failure logs to console but still performs multiplecookieStore.delete
calls wrapped in a silenttry
.
Consider:
- Wrapping the entire fetch in
try/catch
to handle network faults.- Returning typed errors so the caller can react (e.g. show toast).
Optional refactor shown below:
- const res = await fetch(`${NEXT_PUBLIC_NEBULA_URL}/auth/delegate/login`, { + let res: Response; + try { + res = await fetch(`${NEXT_PUBLIC_NEBULA_URL}/auth/delegate/login`, { ... - }); + }); + } catch (err) { + console.error("Network error during login", err); + return { error: "Network error. Please try again later." }; + }apps/nebula/src/app/providers.tsx (1)
11-17
: Share-scopequeryClient
may leak across React treesCreating the
QueryClient
at module scope means a single instance is reused for every SPA mount.
If you ever render the Nebula app inside nested React caches (e.g. in multi-tenant Next.js layouts), stale cache entries could bleed between tenants.Consider memoising inside the component:
-const queryClient = new QueryClient(); +function useSingletonQueryClient() { + const clientRef = useRef<QueryClient>(); + if (!clientRef.current) { + clientRef.current = new QueryClient(); + } + return clientRef.current; +}…and call it at runtime instead of the global variable.
apps/nebula/src/app/(app)/chat/page.tsx (1)
15-18
: Explicitly return afterloginRedirect()
loginRedirect()
presumably throwsredirect()
, yet TS can’t guarantee it.
Addreturn
to satisfy control-flow analysis and future-proof the code:- if (!authToken || !accountAddress) { - loginRedirect(); - } + if (!authToken || !accountAddress) { + return loginRedirect(); + }apps/nebula/src/@/components/ui/Spinner/Spinner.tsx (1)
6-18
: Improve accessibility by labelling the spinnerScreen readers have no semantic hint that this SVG represents a live status indicator. Add
role="status"
and optionallyaria-label="Loading"
to ensure assistive technologies announce it correctly.- <svg - viewBox="0 0 50 50" - className={cn(style.loader, props.className || "size-4")} + <svg + viewBox="0 0 50 50" + role="status" + aria-label="Loading" + className={cn(style.loader, props.className || "size-4")}apps/nebula/src/app/move-funds/move-funds.tsx (1)
82-87
: Consider centralising thedashboardClient
instanceA new
ThirdwebClient
is instantiated every time this module is evaluated. In dev with React Fast Refresh (or if other pages independently callgetClientDashboardThirdwebClient
) this can lead to multiple client instances, duplicated event listeners, and cache fragmentation.If
getClientDashboardThirdwebClient
is not already memoised internally, wrap it in a shared singleton (e.g.,globalThis.__dashboardClient
) or export adashboardClient
from a dedicated module to guarantee one process-wide instance.No action needed if the helper already memoises ▸ please double-check.
apps/nebula/src/@/components/color-mode-toggle.tsx (1)
24-28
: Handle the"system"
theme case explicitly
next-themes
can return"system"
when the user hasn’t chosen a side. Toggling from"system"
will currently switch to"dark"
(since it’s not equal to"dark"
), which may surprise users. A safer toggle:- setTheme(theme === "dark" ? "light" : "dark"); + setTheme(theme === "dark" ? "light" : "dark"); // treat "system" as "light"or map
"system"
to the resolved value viaresolvedTheme
before toggling.apps/nebula/src/@/utils/nebula-chains.ts (1)
13-24
: Cache key does not normalise array order – potential stale hits
unstable_cache
keys are derived fromkeyParts
+ function args. When the caller passes["polygon", "base"]
vs["base", "polygon"]
, the two calls fetch chains in opposite order but generate different keys even though the result set is identical. Normalising the array (e.g.,sort()
) avoids duplicate cache entries and improves hit-rate.- const chainNames = - typeof chainNamesOrIds === "string" ? [chainNamesOrIds] : chainNamesOrIds; + const chainNames = ( + typeof chainNamesOrIds === "string" ? [chainNamesOrIds] : chainNamesOrIds + ).sort(); // normalise for cacheapps/nebula/src/app/(app)/components/ChatPageContent.tsx (2)
624-635
:hasReceivedResponse
guard misses"presence"
-only streamsThe fallback error is triggered when no assistant / image / action frames are received, but a stream that only emits
"presence"
events (e.g. typing indicators) will still flip the flag tofalse
and therefore render the generic error.
Consider treatingpresence
as “activity” or checkingabortController.signal.aborted
before injecting an error.
638-659
: Expose only user-safe error messages
Error.message
can include stack traces, internal URLs or PII coming from the server.
Before displaying it to end-users, map internal errors to a generic string (e.g. “Something went wrong, please try again.”) and log the full object only to observability tooling.- text: `Error: ${error instanceof Error ? error.message : "Failed to execute command"}`, + text: "Something went wrong, please try again.",apps/nebula/.storybook/main.ts (1)
12-18
: Missingaddon-essentials
reduces Storybook DXThe default
@storybook/addon-essentials
bundle (actions, controls, viewport, etc.) is no longer included.
Unless you deliberately excluded it, add it back to avoid losing core functionality:getAbsolutePath("@chromatic-com/storybook"), getAbsolutePath("@storybook/addon-docs"), + getAbsolutePath("@storybook/addon-essentials"),
apps/nebula/src/app/(app)/page.tsx (1)
1-6
: Inconsistent import style & brittle relative pathAll other imports rely on the
@/
alias, butloginRedirect
is fetched via the relative string"../../@/utils/loginRedirect"
, which will break if the file is moved and is harder to grep.-import { loginRedirect } from "../../@/utils/loginRedirect"; +import { loginRedirect } from "@/utils/loginRedirect";apps/nebula/src/@/utils/fetchChain.ts (1)
15-22
: Swallowing JSON-parse errors hides malformed responsesReturning
null
is fine, but silently ignoring bad JSON makes debugging harder.
Log (at least indev
) which chain failed and why.apps/nebula/src/app/(app)/components/Swap/common.tsx (1)
6-7
: Remove dead analytics code to keep the file lean.The
useTrack
import and alltrackEvent
calls are fully commented-out. Keeping large blocks of commented code around quickly turns into noise and makes future refactors harder.-// import { useTrack } from "hooks/analytics/useTrack"; ... - // const trackEvent = useTrack(); ... - // trackEvent({ ... });Unless there is a near-term plan to re-enable analytics, please delete these lines entirely.
Also applies to: 133-147, 155-159, 175-179
apps/nebula/src/@/components/ui/text-shimmer.tsx (1)
1-2
: Use the project-wide alias forcn
for consistency.All other UI components import
cn
via"@/lib/utils"
. Sticking to the same alias keeps search-and-replace and ts-path mappings predictable.-import { cn } from "../../lib/utils"; +import { cn } from "@/lib/utils";apps/nebula/src/@/components/ui/Spinner/Spinner.module.css (1)
4-6
: Duplicateanimation
declaration – first one is never used.Line 4 (
animation: rotate 1s …
) is immediately overridden by line 5 (animation: rotate 2s …
). Remove the redundant rule or decide on a single duration.apps/nebula/src/@/storybook/utils.tsx (1)
29-34
: Typo in parameter name (mesages
).Minor but worth fixing for readability and autocomplete.
-export function storybookLog(...mesages: unknown[]) { +export function storybookLog(...messages: unknown[]) { console.debug(apps/nebula/src/@/components/ui/label.tsx (2)
13-17
:VariantProps
adds no value here – remove to simplify the API
labelVariants
defines no variants, yet the component still exposesVariantProps<typeof labelVariants>
.
This leaks an unnecessary generic into the public type surface and mis-signals that variants exist.- React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & - VariantProps<typeof labelVariants> + React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>If variants are planned in the future, leave a TODO; otherwise drop the extra generic.
26-26
: Consider a default export for consistency with the rest of the UI primitivesMost primitives (
Button
,Input
, …) appear to be default-exported. ExportingLabel
as default avoids asymmetric import ergonomics:-export { Label }; +export default Label;Skip if the codebase intentionally prefers named exports.
apps/nebula/src/@/utils/verifyTurnstileToken.ts (1)
8-10
:headers()
is synchronous – remove the unnecessaryawait
next/headers
exports a synchronous function. Usingawait
on a non-Promise value is tolerated by TS but hurts readability.-const requestHeaders = await headers(); +const requestHeaders = headers();apps/nebula/src/@/constants/public-envs.ts (1)
1-3
: Expose a clear runtime error when the dashboard client ID is not providedSilently defaulting to
""
propagates hidden mis-configuration. Throw or at leastconsole.warn
to aid debugging.-export const NEXT_PUBLIC_DASHBOARD_CLIENT_ID = - process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID || ""; +if (!process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID) { + console.warn("NEXT_PUBLIC_DASHBOARD_CLIENT_ID is not set"); +} +export const NEXT_PUBLIC_DASHBOARD_CLIENT_ID = + process.env.NEXT_PUBLIC_DASHBOARD_CLIENT_ID ?? "";apps/nebula/src/@/components/ui/sonner.tsx (1)
8-29
: Nit: add explicit return type & displayName for devtools clarity.Minor DX touches:
-const Toaster = ({ ...props }: ToasterProps) => { +const Toaster: React.FC<ToasterProps> = (props) => { const { theme = "system" } = useTheme(); … }; + +Toaster.displayName = "NebulaToaster";apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx (1)
3-4
: Prefer alias import over deep relative path for consistency.Other components already use
@/
alias. Switching here avoids long../../../
chains and eases refactors.-import { cn } from "../../../lib/utils"; +import { cn } from "@/lib/utils";apps/nebula/src/@/components/ui/separator.tsx (1)
20-24
: Expose orientation-agnostic base class earlier for easier themingYou hard-code both the base
shrink-0 bg-border
and the orientation-specific sizes in onecn()
call.
If a downstream theme wants to override the background colour but keep the sizing, they must re-declare the whole class list. Splitting the sizing logic out (e.g. via a small helper map) keeps concerns separate and makes theming safer.apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx (1)
30-42
: Overflow test string still fits on many screens — consider adding whitespaceThe very long
overflowText
string lacks whitespace, so most browsers cannot break it and you only test horizontal scrolling.
Appending a space every ~20 chars lets you also verify word-wrap behaviour whenwhite-space
is not forced tonowrap
.apps/nebula/src/@/constants/server-envs.ts (1)
4-7
: Fallback stub leaks silently – add a dev-time warningWhen
experimental_taintUniqueValue
is unavailable you replace it with a no-op.
In non-production Storybook this is fine, but on other non-Next runtimes it could mask an accidental client leak.
Consider logging once so that the absence of the real API is visible during development.-const experimental_taintUniqueValue = - _experimental_taintUniqueValue || (() => {}); +const experimental_taintUniqueValue = + _experimental_taintUniqueValue || + ((...args) => { + if (process.env.NODE_ENV !== "production") { + // eslint-disable-next-line no-console + console.warn( + "experimental_taintUniqueValue is not available – secrets will not be tainted.", + ); + } + });apps/nebula/src/@/components/ui/input.tsx (1)
12-19
: Missing defaulttype
causes unexpected password managers behaviourThe native default for
<input>
istype="text"
, but some password managers treat an unspecifiedtype
as a potential credential field.
Defensively defaulting to"text"
avoids surprises when the consumer forgets to pass atype
.-({ className, type, ...props }, ref) => { +({ className, type = "text", ...props }, ref) => {apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx (1)
45-53
:key={text}
risks duplicate keysIf two reasoning strings are identical React will log a key collision. Use the index or a hash instead.
- {props.texts.map((text) => ( - <li - key={text} + {props.texts.map((text, idx) => ( + <li + key={idx}apps/nebula/src/@/components/ui/popover.tsx (1)
22-24
: Consider exposing motion-reduced variantThe content relies on several
animate-*
utility classes. For accessibility you might expose amotionSafe
prop or respect theprefers-reduced-motion
media query to disable these transitions.apps/nebula/src/@/components/ui/code/getCodeHtml.tsx (2)
23-30
: Dynamic import executed on every call – cache the plugin
import("prettier/plugins/estree")
runs for every invocation ofgetCodeHtml
, producing unnecessary network / bundle hits.
Store the promise outside the function so it resolves once.-export async function getCodeHtml( +const estreePluginPromise = import("prettier/plugins/estree"); + +export async function getCodeHtml( ... - plugins: [parserBabel, estreePlugin.default], + plugins: [parserBabel, (await estreePluginPromise).default],
25-41
:format()
errors bubble only for Prettier – wrapcodeToHtml
too
codeToHtml
can also throw (e.g. unsupported language). Consider symmetric error handling to avoid unhandled promise rejections:- const html = await codeToHtml(formattedCode, { + let html; + try { + html = await codeToHtml(formattedCode, { ... - }); + }); + } catch (e) { + if (!options?.ignoreFormattingErrors) console.error(e); + html = formattedCode; // graceful fallback + }apps/nebula/src/@/components/ui/DynamicHeight.tsx (1)
47-55
: Initial height flash
ResizeObserver
fires after paint, causing a brief “auto-height” flash.
Set height synchronously on mount to avoid layout shift:useIsomorphicLayoutEffect(() => { const element = elementRef.current; if (!element) return; - const resizeObserver = new ResizeObserver(() => { - setHeight(element.scrollHeight); - }); + // set immediately + setHeight(element.scrollHeight); + + const resizeObserver = new ResizeObserver(() => + setHeight(element.scrollHeight), + );apps/nebula/src/@/hooks/chains.ts (1)
100-110
: Store never refreshes after the first successful load
useEffect
bails out onceallChainsStore
is populated, so later hooks mounted
after a tab is inactive, or a hard-refresh of the data in the background,
will never see updated chain metadata.
Consider persisting a timestamp/version in the store and re-running
updateAllChainsStore
whenallChainsQuery.data
differs.apps/nebula/src/@/components/ui/textarea.tsx (1)
29-36
: Switch touseLayoutEffect
to eliminate resize flickerHeight recalculation needs to run before the browser paints; otherwise the
textarea briefly collapses to the old height and causes a visual jump.- React.useEffect(() => { + React.useLayoutEffect(() => {apps/nebula/src/@/components/blocks/FormFieldSetup.tsx (1)
6-14
:isRequired
should be optional with a sane defaultRequiring callers to always pass
isRequired
results in noisy JSX (isRequired={false}
).
Default tofalse
and make the prop optional.- isRequired: boolean; + isRequired?: boolean;Inside the component:
-{props.isRequired && ( +{props.isRequired && ((unchanged logic – still renders only when truthy)
apps/nebula/src/@/components/ui/code/plaintext-code.tsx (1)
24-27
: Consider wrapping the<code>
element in a<pre>
for semantic correctness
<code>
alone is valid, but using a<pre>
+<code>
pair is the conventional, semantics-friendly way to display pre-formatted blocks. Browsers and assistive technologies expect this structure, and it can prevent edge-case whitespace handling issues.- <code className={cn("block whitespace-pre", props.codeClassName)}> - {props.code} - </code> + <pre className="whitespace-pre"> + <code className={cn("block", props.codeClassName)}> + {props.code} + </code> + </pre>apps/nebula/src/@/components/ui/code/code.stories.tsx (1)
95-106
: Duplicate “tsx” label may confuse Storybook consumers
Both of these badges are labelled"tsx"
, yet the second block intentionally contains a syntax error. Renaming the second label (e.g.,"tsx-error"
) will make the showcase clearer.- <BadgeContainer label="tsx"> + <BadgeContainer label="tsx-error"> <CodeClient code={tsxCodeWithFormError} lang="tsx" /> </BadgeContainer>apps/nebula/src/@/components/ui/button.stories.tsx (1)
6-10
: Move metadata declaration below component to avoid reliance on hoisting
meta
referencesComponent
before it is declared. While function hoisting makes this work, placing metadata after the story components (or movingComponent
above) improves readability and prevents accidental circular-reference issues during refactors.-const meta = { - title: "Shadcn/Buttons", - component: Component, -} satisfies Meta<typeof Component>; +const meta: Meta<typeof Component> = { + title: "Shadcn/Buttons", + component: Component, +};apps/nebula/src/@/constants/urls.ts (1)
23-24
: Inconsistent constant naming –.URL
vs.DOMAIN
Every constant except
THIRDWEB_BRIDGE_URL
is suffixed with_DOMAIN
, yet it uses_URL
. Either rename this constant or rename the others for consistency:-export const THIRDWEB_BRIDGE_URL = +export const THIRDWEB_BRIDGE_DOMAIN = process.env.NEXT_PUBLIC_BRIDGE_URL || "bridge.thirdweb-dev.com";apps/nebula/src/@/components/ui/sheet.tsx (1)
33-44
: Border colour without width – won’t render a border
border-border
only sets the border colour; no width is applied. Unless you rely on a global* { border-width: 1px }
, the Sheet will appear border-less. Consider adding an explicit width utility:-"fixed z-50 gap-4 bg-background p-6 shadow-lg ... + "fixed z-50 gap-4 bg-background p-6 shadow-lg border ...or use
border
/border-*
together withborder-border
.apps/nebula/src/@/components/ui/NavLink.tsx (1)
24-28
: Prefix matching may produce false positives
pathname.startsWith(props.href)
marks/apple
active for a link to/app
. Use a trailing slash or regex to prevent accidental matches.const normalizedHref = props.href.endsWith("/") ? props.href : `${props.href}/`; const isActive = pathname ? props.exactMatch ? pathname === props.href : pathname.startsWith(normalizedHref) : false;apps/nebula/src/@/components/blocks/ChainIcon.tsx (1)
15-17
: Large inline base64 string bloats bundleThe ~4 KB base64 SVG in code increases JS payload. Store it in
/public
or import as an asset and let the bundler optimise caching.-const fallbackChainIcon = "data:image/svg+xml;base64,..."; +import fallbackChainIcon from "@/assets/fallback-chain.svg"; // webpack/next will inline or cache appropriatelyapps/nebula/src/@/components/ui/decimal-input.tsx (1)
26-28
: Edge-case:maxValue
check skipped whenmaxValue = 0
if (props.maxValue && number > props.maxValue)
short-circuits whenmaxValue
is0
, wrongly allowing any negative number.
Useprops.maxValue !== undefined
instead:- if (props.maxValue && number > props.maxValue) { + if (props.maxValue !== undefined && number > props.maxValue) { return; }apps/nebula/src/@/types/chain.ts (1)
13-17
: Redundant state –enabled
vsstatus
can diverge
enabled: boolean
andstatus: "enabled" | "disabled"
encode the same information twice.
Keeping both invites inconsistency (enabled: true, status: "disabled"
). Prefer a single source of truth.-type ChainService = { - service: ChainSupportedService; - enabled: boolean; - status: "enabled" | "disabled"; -}; +type ChainService = { + service: ChainSupportedService; + status: "enabled" | "disabled"; +};apps/nebula/src/@/components/ui/CopyTextButton.tsx (1)
9-14
:tooltip
shouldn’t be requiredThe prop is typed as mandatory yet callers may reasonably omit it.
Mark it optional to match usage elsewhere:- tooltip: string | undefined; + tooltip?: string;apps/nebula/src/@/components/ui/badge.tsx (1)
33-36
: Semantic element – prefer<span>
for inline badgeBadges are inline, non-interactive decoration; using a
<div>
breaks semantic flow and can affect screen-reader punctuation. A<span>
(orrole="status"
) avoids block-level side effects.- <div className={cn(badgeVariants({ variant }), className)} {...props} /> + <span className={cn(badgeVariants({ variant }), className)} {...props} />apps/dashboard/src/components/CustomChat/ChatBar.tsx (2)
14-24
:client
prop & import are unused – safe to delete
ThirdwebClient
is imported (l. 14) and exposed viaprops.client
(l. 23) but never referenced inside the component. This will triggerno-unused-vars
/@typescript-eslint/no-unused-vars
lints and bloats the public API.-import type { ThirdwebClient } from "thirdweb"; ... - client: ThirdwebClient;If future work really needs the client, keep it and at least
/** @deprecated */
‐annotate to silence the linter; otherwise drop it.
118-125
: Minor duplication – delegate validation tohandleSubmit
handleSubmit
currently sends any string; the button performs its own trimming logic. LethandleSubmit
own the validation to avoid drift:- if (message.trim() === "") return; - handleSubmit(message); + handleSubmit(message.trim());and inside
handleSubmit
early-return whenmessage === ""
.apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx (1)
39-55
: Missing accessible label for copy buttonScreen-reader users won’t know what the button does.
- <Button + <Button + aria-label={hasCopied ? "Code copied" : "Copy code"}Simple, zero-cost accessibility win.
apps/nebula/src/@/components/blocks/Img.stories.tsx (1)
14-16
: Naming collision betweenStory
(value) andStory
(type alias)Because TS splits the type/value namespaces this works, but it is needlessly confusing for future maintainers skimming the file. Renaming one of them (e.g.
StoryComponent
orImgStory
) removes the mental overhead.apps/nebula/src/@/components/ui/skeleton.tsx (1)
15-23
: Consider explicitnull
handling forloadedData
Only
undefined
is treated as “not loaded”. If callers legitimately returnnull
, the skeleton never disappears. Either clarify in docs or widen the check:-const isLoading = props.loadedData === undefined; +const isLoading = props.loadedData == null; // matches undefined | nullapps/nebula/src/@/components/ui/dialog.tsx (2)
38-45
: Double‐destructuring ofprops
is brittle
className
andchildren
are already pulled out in the outer destructuring, thenprops
is split again intodialogOverlayClassName
, etc. This works today but is easy to break if new props are added.
Prefer extracting once to avoid silent shadowing:>({ className, children, dialogOverlayClassName, dialogCloseClassName, ...rest }, ref)
62-70
: Accessibility: addaria-label
to close buttonScreen-reader only text is present, but adding an explicit
aria-label="Close dialog"
helps assistive tech that ignores visually-hidden spans.- <DialogPrimitive.Close + <DialogPrimitive.Close + aria-label="Close dialog"apps/nebula/src/@/components/ui/select.stories.tsx (1)
25-27
: Random key collisions possible
randomName()
can return duplicates, generating duplicate keys forSelectItem
in rare cases. Using an index (i
) that is already available avoids this.Array.from({length:n}, (_, i) => `item-${i}`)apps/nebula/src/@/components/blocks/multi-select.stories.tsx (1)
34-35
: Rendering 5 000 options synchronously may freeze StorybookA list of 5 000 React nodes is rendered immediately in the “5000 items” variant.
For realistic UX and Storybook performance, virtualise or lazy-load the list, or cut it down to a representative size (e.g. 200).apps/nebula/src/@/components/ui/table.stories.tsx (2)
11-15
: Prefer absolute import forcn
for consistencyMost files in the new Nebula package use the “@” alias for absolute imports (e.g.
@/lib/utils
). This line falls back to a brittle relative path. Switching to the alias keeps the path stable if the file is moved or nested deeper.-import { cn } from "../../lib/utils"; +import { cn } from "@/lib/utils";
29-45
: Consider extractingTableDemo
to reduce copy-paste across stories
TableDemo
is defined inline but reused three times. Moving it intoapps/nebula/src/@/components/ui/table-demo.tsx
(or astories/helpers
folder) keeps the story file focused on story configuration and makes the demo component reusable by other stories/tests.apps/nebula/src/@/components/blocks/select-with-search.tsx (2)
71-100
: Replace manualfor
loop withArray.prototype.filter + slice
The current loop is imperative and harder to read. A declarative approach is shorter and less error-prone:
-const filteredOptions: { label: string; value: string }[] = []; -const searchValLowercase = searchValue.toLowerCase(); -for (let i = 0; i <= options.length - 1; i++) { - if (filteredOptions.length >= itemsToShow) break; - const option = options[i]; - if (!option) continue; - if (overrideSearchFn - ? overrideSearchFn(option, searchValLowercase) - : option.label.toLowerCase().includes(searchValLowercase)) { - filteredOptions.push(option); - } -} -return filteredOptions; +const searchVal = searchValue.toLowerCase(); +return options + .filter((o) => + overrideSearchFn + ? overrideSearchFn(o, searchVal) + : o.label.toLowerCase().includes(searchVal), + ) + .slice(0, itemsToShow);
88-96
:overrideSearchFn
receives a lower-cased term – document thisThe component lower-cases
searchValue
before passing it to the override, which is convenient but surprising. Either document this behaviour in the prop JSDoc or pass the raw term and let the override decide.apps/dashboard/src/components/CustomChat/types.ts (1)
7-13
: TODO still present – rename or drop “Nebula” terminologyThe dashboard now owns its own chat implementation; leaving Nebula-specific names invites confusion. Consider:
-// TODO - remove "Nebula" wording and simplify types -export type NebulaContext = { … } +export type ChatContext = { … }and adjust downstream imports.
apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx (1)
4-13
: Minor: story meta usesStory
before its declarationFunction declarations are hoisted so this compiles, but it hurts readability. Consider moving the
function Story
definition above themeta
object to avoid forward-reference surprises.apps/nebula/src/global.css (1)
148-160
: Utility class can leak outside Tailwind tree-shakingThe
.no-scrollbar *
selector matches every descendant and prevents scrollbar rendering even inside embedded third-party widgets. Consider scoping to elements you own (e.g..app-no-scrollbar
) to avoid unintended side-effects.apps/nebula/.storybook/preview.tsx (1)
77-80
: Overwritingdocument.body.className
nukes existing classes
document.body.className = …
replaces any classes Storybook might already set (e.g. dark/light background tweak extensions). Prefer additive logic:- document.body.className = `font-sans antialiased ${fontSans.variable}`; + document.body.classList.add("font-sans", "antialiased", fontSans.variable);Prevents accidental removal of other runtime classes.
apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx (1)
69-74
: NestedrequestAnimationFrame
is redundantCalling
rAF
twice back-to-back adds ~16 ms delay but no functional benefit. A single call is sufficient:- requestAnimationFrame(() => { - requestAnimationFrame(() => { - handleScroll(); - }); - }); + requestAnimationFrame(handleScroll);Simplifies the mount path and removes one paint delay.
apps/nebula/src/@/components/ui/table.tsx (2)
6-18
: Missing basic accessibility roles / attributes on the<table>
elementForward-ref’ing the native
<table>
is fine, but the component does not set any ARIA roles orrole="table"
/aria-label
/aria-describedby
attributes, so a consumer must remember to add them each time. Consider surfacing acaption
prop or at least passing-througharia-label
to improve a11y defaults.
70-80
:linkBox
implementation slightly brittleRelying on
relative translate-x-0 translate-y-0
to “activate” positioning is clever but non-obvious. A clearer approach is to toggle a data-attribute and keep all styling in CSS:- linkBox && "relative translate-x-0 translate-y-0", + linkBox && "relative",and in your CSS utilities scope
[data-link-box="true"]
if you really need transforms.apps/nebula/src/@/components/blocks/wallet-address.tsx (2)
30-38
: Guard against very short / undefined addresses
address.slice(0, 6)
assumes the string has at least 6 characters.
Ifprops.address
is an empty string this will throw. Add a length check or fall back:-? `${address.slice(0, 6)}...${address.slice(-4)}` +? address.length > 10 + ? `${address.slice(0, 6)}...${address.slice(-4)}` + : address
126-166
:key
may collide when two profiles share the same name & type
key={profile.type + profile.name}
is not guaranteed unique.
Safer:-key={profile.type + profile.name} +key={`${profile.type}-${profile.name}-${profile.id ?? profile.avatar}`}apps/nebula/src/@/components/ui/tooltip.tsx (1)
46-69
: NestedTooltipProvider
s created on every render
ToolTipLabel
wraps each call site in its ownTooltipProvider
. This is usually unnecessary and creates extra context providers. Export a singletonTooltipProvider
at the app root and remove the wrapper here, or memoise the provider instance.apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx (1)
172-180
:disabled
state can lie when balance query errors
disabled
ignorestxChainBalance.isError
– the user can press the button and hit runtime errors. Include the error status:- (!showSwitchChainPopover && txChainBalance.isPending && isBalanceRequired); + (!showSwitchChainPopover && (txChainBalance.isPending || txChainBalance.isError) && isBalanceRequired);apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx (1)
54-60
:initialFocusRef
is never used – dead code & unnecessary re-renders.You create the ref and pass it to
ExternalApprovalNotice
, but that component ignores the prop entirely.
Removing the ref (and the prop forwarding) avoids an extra render dependency and keeps the API surface minimal.- const initialFocusRef = useRef<HTMLButtonElement>(null); ... - <ExternalApprovalNotice - walletId={activeWallet?.id} - initialFocusRef={initialFocusRef} - /> + <ExternalApprovalNotice walletId={activeWallet?.id} />…and drop the
initialFocusRef
field fromExternalApprovalNoticeProps
.apps/nebula/src/@/components/blocks/multi-select.tsx (1)
152-160
: Ignoring exhaustive-deps can bite – stale scroll reset logic.The comment suppresses the linter but the effect depends on
optionsToShow
AND popover open state, not onlysearchValue
. Consider:- }, [searchValue]); + }, [searchValue, optionsToShow, isPopoverOpen]);…or refactor to an imperative
scrollToTop()
called right after options calculation.apps/nebula/src/@/components/blocks/NetworkSelectors.tsx (1)
11-13
:cleanChainName
leaves a trailing space.
"Polygon Mainnet"
→"Polygon "
.-return chainName.replace("Mainnet", ""); +return chainName.replace("Mainnet", "").trim();apps/nebula/src/@/components/ui/tabs.tsx (1)
40-78
: Addrole="tablist"
/role="tab"
for accessibilityScreen-reader users currently get generic buttons/links.
Wrap the flex container withrole="tablist"
and give each tabrole="tab"
plusaria-selected={isActive}
.
This is a low-effort change that makes the component fully perceivable.Also applies to: 112-154
apps/nebula/src/@/components/ui/form.tsx (1)
105-127
:RequiredFormLabel.displayName
is never setLine 127 sets
FormLabel.displayName
(again) instead of
RequiredFormLabel.displayName
, so the required variant shows up as “Anonymous” in React DevTools.-FormLabel.displayName = "FormLabel"; +RequiredFormLabel.displayName = "RequiredFormLabel";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/nebula/src/app/opengraph-image.png
is excluded by!**/*.png
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (188)
apps/dashboard/.env.example
(0 hunks)apps/dashboard/package.json
(0 hunks)apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/client-only.tsx
(1 hunks)apps/dashboard/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/dashboard/src/@/constants/public-envs.ts
(0 hunks)apps/dashboard/src/@/constants/server-envs.ts
(0 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/login/LoginPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx
(1 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
(0 hunks)apps/dashboard/src/app/nebula-app/nebula-global.css
(0 hunks)apps/dashboard/src/app/nebula-app/readme.md
(0 hunks)apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
(0 hunks)apps/dashboard/src/components/CustomChat/ChatBar.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChatContent.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChats.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/types.ts
(1 hunks)apps/dashboard/src/components/explore/contract-card/index.tsx
(1 hunks)apps/dashboard/src/middleware.ts
(0 hunks)apps/dashboard/src/stories/stubs.ts
(0 hunks)apps/nebula/.env.example
(1 hunks)apps/nebula/.eslintignore
(1 hunks)apps/nebula/.eslintrc.js
(1 hunks)apps/nebula/.storybook/main.ts
(1 hunks)apps/nebula/.storybook/preview.tsx
(1 hunks)apps/nebula/LICENSE.md
(1 hunks)apps/nebula/README.md
(1 hunks)apps/nebula/biome.json
(1 hunks)apps/nebula/components.json
(1 hunks)apps/nebula/knip.json
(1 hunks)apps/nebula/lucide-react.d.ts
(1 hunks)apps/nebula/next-env.d.ts
(1 hunks)apps/nebula/next-sitemap.config.js
(1 hunks)apps/nebula/next.config.ts
(1 hunks)apps/nebula/package.json
(1 hunks)apps/nebula/postcss.config.js
(1 hunks)apps/nebula/src/@/components/blocks/ChainIcon.tsx
(1 hunks)apps/nebula/src/@/components/blocks/FormFieldSetup.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MultiNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/NetworkSelectors.tsx
(1 hunks)apps/nebula/src/@/components/blocks/SingleNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/auto-connect.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/client-only.tsx
(2 hunks)apps/nebula/src/@/components/blocks/multi-select.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/multi-select.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.tsx
(1 hunks)apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx
(1 hunks)apps/nebula/src/@/components/blocks/wallet-address.tsx
(1 hunks)apps/nebula/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/nebula/src/@/components/ui/CopyTextButton.tsx
(1 hunks)apps/nebula/src/@/components/ui/DynamicHeight.tsx
(1 hunks)apps/nebula/src/@/components/ui/NavLink.tsx
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.module.css
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.tsx
(1 hunks)apps/nebula/src/@/components/ui/avatar.tsx
(1 hunks)apps/nebula/src/@/components/ui/badge.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/RenderCode.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.client.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/getCodeHtml.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/decimal-input.tsx
(1 hunks)apps/nebula/src/@/components/ui/dialog.tsx
(1 hunks)apps/nebula/src/@/components/ui/form.tsx
(1 hunks)apps/nebula/src/@/components/ui/hover-card.tsx
(1 hunks)apps/nebula/src/@/components/ui/inline-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/input.tsx
(1 hunks)apps/nebula/src/@/components/ui/label.tsx
(1 hunks)apps/nebula/src/@/components/ui/popover.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.tsx
(1 hunks)apps/nebula/src/@/components/ui/separator.tsx
(1 hunks)apps/nebula/src/@/components/ui/sheet.tsx
(1 hunks)apps/nebula/src/@/components/ui/skeleton.tsx
(1 hunks)apps/nebula/src/@/components/ui/sonner.tsx
(1 hunks)apps/nebula/src/@/components/ui/switch.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.tsx
(1 hunks)apps/nebula/src/@/components/ui/tabs.tsx
(1 hunks)apps/nebula/src/@/components/ui/text-shimmer.tsx
(1 hunks)apps/nebula/src/@/components/ui/textarea.tsx
(1 hunks)apps/nebula/src/@/components/ui/tooltip.tsx
(1 hunks)apps/nebula/src/@/config/sdk-component-theme.ts
(1 hunks)apps/nebula/src/@/constants/env-utils.ts
(1 hunks)apps/nebula/src/@/constants/local-node.ts
(1 hunks)apps/nebula/src/@/constants/nebula-client.ts
(1 hunks)apps/nebula/src/@/constants/public-envs.ts
(1 hunks)apps/nebula/src/@/constants/server-envs.ts
(1 hunks)apps/nebula/src/@/constants/urls.ts
(1 hunks)apps/nebula/src/@/data/eth-sanctioned-addresses.ts
(1 hunks)apps/nebula/src/@/hooks/chains.ts
(1 hunks)apps/nebula/src/@/hooks/use-clipboard.tsx
(1 hunks)apps/nebula/src/@/icons/NebulaIcon.tsx
(1 hunks)apps/nebula/src/@/lib/DashboardRouter.tsx
(1 hunks)apps/nebula/src/@/lib/reactive.ts
(1 hunks)apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts
(1 hunks)apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts
(1 hunks)apps/nebula/src/@/lib/useShowMore.ts
(1 hunks)apps/nebula/src/@/lib/utils.ts
(1 hunks)apps/nebula/src/@/storybook/stubs.ts
(1 hunks)apps/nebula/src/@/storybook/utils.tsx
(1 hunks)apps/nebula/src/@/types/chain.ts
(1 hunks)apps/nebula/src/@/utils/authToken.ts
(1 hunks)apps/nebula/src/@/utils/fetchChain.ts
(1 hunks)apps/nebula/src/@/utils/loginRedirect.ts
(1 hunks)apps/nebula/src/@/utils/map-chains.ts
(1 hunks)apps/nebula/src/@/utils/nebula-chains.ts
(1 hunks)apps/nebula/src/@/utils/parse-error.tsx
(1 hunks)apps/nebula/src/@/utils/vercel-utils.ts
(1 hunks)apps/nebula/src/@/utils/verifyTurnstileToken.ts
(1 hunks)apps/nebula/src/app/(app)/api/chat.ts
(1 hunks)apps/nebula/src/app/(app)/api/feedback.ts
(1 hunks)apps/nebula/src/app/(app)/api/session.ts
(1 hunks)apps/nebula/src/app/(app)/api/types.ts
(1 hunks)apps/nebula/src/app/(app)/chat/[session_id]/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/page.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatBar.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageContent.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatSidebar.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chatbar.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.tsx
(1 hunks)apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx
(2 hunks)apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx
(4 hunks)apps/nebula/src/app/(app)/components/Swap/common.tsx
(6 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/data/examplePrompts.ts
(2 hunks)apps/nebula/src/app/(app)/layout.tsx
(1 hunks)apps/nebula/src/app/(app)/page.tsx
(1 hunks)apps/nebula/src/app/(app)/utils/getChainIds.ts
(1 hunks)apps/nebula/src/app/layout.tsx
(2 hunks)apps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx
(1 hunks)apps/nebula/src/app/login/NebulaLoginPage.tsx
(1 hunks)apps/nebula/src/app/login/auth-actions.ts
(1 hunks)apps/nebula/src/app/login/page.tsx
(1 hunks)apps/nebula/src/app/move-funds/connect-button.tsx
(1 hunks)apps/nebula/src/app/move-funds/dashboard-client.ts
(1 hunks)apps/nebula/src/app/move-funds/move-funds.tsx
(4 hunks)apps/nebula/src/app/move-funds/page.tsx
(1 hunks)apps/nebula/src/app/not-found.tsx
(2 hunks)apps/nebula/src/app/providers.tsx
(2 hunks)apps/nebula/src/global.css
(1 hunks)apps/nebula/tailwind.config.js
(1 hunks)apps/nebula/tsconfig.json
(1 hunks)apps/nebula/vercel.json
(1 hunks)
💤 Files with no reviewable changes (12)
- apps/dashboard/package.json
- apps/dashboard/src/@/constants/public-envs.ts
- apps/dashboard/src/app/nebula-app/nebula-global.css
- apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
- apps/dashboard/.env.example
- apps/dashboard/src/@/constants/server-envs.ts
- apps/dashboard/src/app/nebula-app/readme.md
- apps/dashboard/src/stories/stubs.ts
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
- apps/dashboard/src/middleware.ts
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
🧰 Additional context used
🧠 Learnings (2)
apps/nebula/src/@/utils/loginRedirect.ts (1)
Learnt from: MananTank
PR: thirdweb-dev/js#7228
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/in-app-wallets/settings/page.tsx:23-25
Timestamp: 2025-05-30T18:14:57.074Z
Learning: In the dashboard codebase, the `loginRedirect` function performs an actual page redirect that automatically stops execution, similar to Next.js `redirect()`. No return statement is needed after calling `loginRedirect` as it handles flow control internally.
apps/nebula/src/@/components/blocks/Img.tsx (1)
Learnt from: MananTank
PR: thirdweb-dev/js#7177
File: apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/public-pages/erc20/_components/ContractHeader.tsx:26-43
Timestamp: 2025-05-29T10:49:52.981Z
Learning: In React image components, conditional rendering of the entire image container (e.g., `{props.image && <Img />}`) serves a different purpose than fallback handling. The conditional prevents rendering any image UI when no image metadata exists, while the fallback prop handles cases where image metadata exists but the image fails to load. This pattern is intentional to distinguish between "no image intended" vs "image intended but failed to load".
🪛 Gitleaks (8.26.0)
apps/nebula/src/@/constants/local-node.ts
5-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 dotenv-linter (3.3.0)
apps/nebula/.env.example
[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
🪛 LanguageTool
apps/nebula/LICENSE.md
[uncategorized] ~150-~150: Possible missing comma found.
Context: ...iateness of using or redistributing the Work and assume any risks associated wit...
(AI_HYDRA_LEO_MISSING_COMMA)
[style] ~161-~161: ‘any and all’ might be wordy. Consider a shorter alternative.
Context: ...ge, computer failure or malfunction, or any and all other commercial damages or losses)...
(EN_WORDINESS_PREMIUM_ANY_AND_ALL)
🔇 Additional comments (67)
apps/nebula/next-env.d.ts (1)
1-5
: Standard Next.js env typings – LGTMGenerated declaration file looks correct and is safe to commit. No action needed.
apps/nebula/knip.json (3)
3-3
: Verify thenext
feature toggle.Ensure that enabling
"next": true
is intentional and aligns with your project’s Knip usage, as it may turn on experimental features.
4-5
: Confirmignore
andproject
patterns.Verify that
src/**
correctly targets the Nebula-app source directory (relative to this config) and that ignoringsrc/@/components/ui/**
doesn’t exclude files you still want analyzed.
6-7
: Review ignored binaries and dependencies.Double-check that skipping
only-allow
,biome
, and thethirdweb
dependency is deliberate, so no essential binaries or imports are omitted from Knip’s analysis.apps/nebula/vercel.json (1)
1-5
: Configuration file looks good
The Vercel deployment config enables automatic cancellation of redundant GitHub jobs as intended.apps/nebula/biome.json (1)
1-16
: Biome override config is correct
The schema reference, extends path, and rule override fornoImportantInKeyframe
are properly defined.apps/nebula/postcss.config.js (1)
1-6
: PostCSS config is valid
The Tailwind CSS and Autoprefixer plugins are correctly configured for the Nebula app’s build pipeline.apps/nebula/next.config.ts (1)
8-16
: Re-evaluate permissive CSP directives ('unsafe-inline'
,'unsafe-eval'
)Including
'unsafe-inline'
and'unsafe-eval'
instyle-src
andscript-src
weakens XSS protection and may fail certain compliance checks. If they are required (e.g., for third-party widgets), consider:
- Moving inline code to hashed or nonce-based scripts/styles.
- Limiting
'unsafe-eval'
usage to development only via dynamic header values.Tightening these directives will appreciably increase the security posture.
apps/nebula/package.json (1)
45-47
: Double-check React 19 compatibility with Next 15 before merge
"react": "19.1.0"
and"react-dom": "19.1.0"
target the upcoming React 19 release.
Next 15.3.x currently ships experimental React 19 support; if your CI still builds against stable channels this may break. Verify lockfile / CI image uses the matchingcanary
orexperimental
tag of Next.apps/nebula/.eslintignore (1)
1-14
: LGTM – sensible ignore listNothing to add; the ignore list covers common build artefacts.
apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx (1)
1-1
: Import-alias change looks good.The move to
@/storybook/stubs
matches the new alias pattern adopted across the repo. Ensure the alias is declared in bothtsconfig.json
and Storybook’s webpack/TS config so CI doesn’t break.apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx (1)
1-1
: Alias update acknowledged.Same note as above: verify Storybook & Jest path-mappings include
@/storybook/*
.apps/nebula/src/app/move-funds/page.tsx (1)
2-2
: LGTM – absolute import adds clarity.No functional change; complies with new module-alias convention.
apps/nebula/src/app/login/NebulaLoginPage.tsx (1)
5-5
: Import path updated correctly.Just ensure
@/icons/NebulaIcon
is re-exported from a single location to avoid duplicate bundles.apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx (1)
1-1
: Ensure@/storybook/*
alias is configured for both Vite & TS.The new absolute import will fail at both type-check and runtime if
paths
intsconfig.json
and the corresponding Storybook/Webpack/Vite alias are not updated (or were never present for the Nebula package scope).#!/bin/bash # Verify that a path alias for "@/storybook/*" exists in any tsconfig* rg --no-heading --line-number --glob 'tsconfig*.json' '"@/storybook/*"' -n # Verify Storybook/vite alias (search vite.config or main.ts) rg --no-heading --line-number -e '@/storybook/utils' -g '*vite*.{ts,js}' -g '*main*.{ts,js}'apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx (1)
1-1
: ```shell
#!/bin/bash
set -eecho "=== apps/dashboard/tsconfig.json compilerOptions (first 50 lines) ==="
sed -n '1,50p' apps/dashboard/tsconfig.json || echo "→ apps/dashboard/tsconfig.json not found"echo -e "\n=== root tsconfig.json compilerOptions (first 50 lines) ==="
sed -n '1,50p' tsconfig.json || echo "→ root tsconfig.json not found"echo -e "\n=== Alias configuration in next.config.js files ==="
find . -type f -name 'next.config.js' -print -exec sed -n '/alias/,/}/p' {} ; | sed '/^$/d'</details> <details> <summary>apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx (1)</summary> `1-1`: **Import alias looks good – confirm `@` alias coverage for _all_ build targets** The switch to the project-wide alias improves readability. Quick sanity-check: make sure the alias is declared in every relevant `tsconfig.json` **and** in any Jest/Vite/ESLint tooling configs for the dashboard app so local dev, CI and storybook builds don’t break. </details> <details> <summary>apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx (1)</summary> `3-3`: **Consistent aliasing 👍** No functional change – import is now aligned with the new shared location of `ClientOnly`. Same remark as above: ensure `paths` / module-resolver config for the dashboard app includes `"@/components/*"`. </details> <details> <summary>apps/dashboard/src/@/components/Responsive.tsx (1)</summary> `2-2`: **Alias update acknowledged** Looks good. Since this component is compiled on the client (`"use client"`), nothing else to flag. </details> <details> <summary>apps/nebula/src/app/(app)/utils/getChainIds.ts (1)</summary> `1-1`: **Verify Nebula’s `@` path mapping** Nebula now resolves `@/utils/fetchChain`. Confirm the Nebula app’s own `tsconfig.json` (and next-js `paths` / webpack `alias`) includes the root-level mapping, otherwise the build will fail when apps are built in isolation. </details> <details> <summary>apps/dashboard/src/components/explore/contract-card/index.tsx (1)</summary> `1-1`: **Import path modernised** Nothing further – import path matches the new component location. </details> <details> <summary>apps/nebula/src/app/(app)/api/chat.ts (1)</summary> `3-3`: **Check that ‘NebulaUserMessage’ is now exported from `./types`.** The import path was updated, so compilation now depends on `NebulaUserMessage` (and `NebulaTxData`) being re-exported from `apps/nebula/src/app/(app)/api/types.ts`. Please run `tsc --noEmit` or your IDE to ensure the symbol really exists; otherwise the build will break. </details> <details> <summary>apps/nebula/src/app/(app)/api/feedback.ts (1)</summary> `2-2`: **Import path change looks good – confirm the helper file lives alongside.** `fetchWithAuthToken` is now imported relatively. Make sure the helper was actually moved into the same directory; otherwise you will hit a runtime 404 when the bundle is generated. </details> <details> <summary>apps/dashboard/src/@/components/color-mode-toggle.tsx (1)</summary> `3-3`: **LGTM – import switched to the new alias path.** </details> <details> <summary>apps/nebula/src/app/(app)/api/session.ts (1)</summary> `3-3`: **Consistent with feedback.ts – verify helper location.** Same note as in `feedback.ts`: ensure `fetchWithAuthToken` really sits in the same folder; otherwise this will break at build time. </details> <details> <summary>apps/dashboard/src/app/(app)/login/LoginPage.tsx (1)</summary> `4-4`: **Import path migrated – looks correct.** </details> <details> <summary>apps/nebula/src/app/(app)/chat/history/page.tsx (1)</summary> `1-2`: **Absolute-path alias switch looks correct** Importing via the `@/` alias keeps paths short and resilient to future directory moves. No further action required. </details> <details> <summary>apps/nebula/src/app/login/page.tsx (1)</summary> `1-2`: **Alias import refactor OK** The transition to absolute aliases improves readability and is consistent with the rest of the PR. </details> <details> <summary>apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx (1)</summary> `5-5`: **Import path update validated** Switching to `@/components/blocks/client-only` aligns with the new shared `ClientOnly` implementation—good cleanup. </details> <details> <summary>apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx (1)</summary> `3-3`: **Consistent alias import – looks good** The new `ClientOnly` alias keeps imports maintainable and removes the previous brittle relative path chain. </details> <details> <summary>apps/nebula/src/app/(app)/components/Chats.stories.tsx (1)</summary> `1-2`: **Storybook imports modernised successfully** Absolute aliases for story utilities/stubs improve DX; no issues spotted. </details> <details> <summary>apps/dashboard/src/components/CustomChat/CustomChats.tsx (1)</summary> `12-12`: **Import fix LGTM** Relative import now matches colocated `Reasoning.tsx`; compilation should succeed. </details> <details> <summary>apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx (1)</summary> `5-5`: **Alias switch is welcome – confirm tsconfig is wired** Good move to the `@/` alias. Just double-check that `tsconfig.json` (and `jest/webpack` configs if present) include the `@/*` mapping so this resolves in all tooling. </details> <details> <summary>apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx (1)</summary> `16-16`: **Import path updated correctly** `NebulaIcon` now lives under the dashboard chain icons – looks consistent with other icons imported above. </details> <details> <summary>apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx (1)</summary> `5-5`: **Alias migration acknowledged** Same note as for the NFT fieldset: alias is cleaner, be sure all build and test configs are aware of `@/`. </details> <details> <summary>apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx (1)</summary> `1-1`: **Import-alias migration looks solid** Switching from relative to aliased `"@/storybook/utils"` keeps the storybook codebase consistent with the new absolute-import convention. No further action required. </details> <details> <summary>apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx (1)</summary> `4-6`: **Good move to absolute paths** The switch to `@/constants/nebula-client` and `@/icons/NebulaIcon` removes an extra `../` hop and matches the rest of the refactor. 👍 </details> <details> <summary>apps/nebula/src/app/(app)/components/ChatBar.tsx (1)</summary> `3-4`: **Import path updates LGTM** `ChainIconClient` and `useAllChainsData` are still referenced later in the file and the new aliased locations compile fine. Nice cleanup. Also applies to: 19-20 </details> <details> <summary>apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx (1)</summary> `5-7`: **LGTM – import path update matches new alias** No functional changes; alias looks correct. </details> <details> <summary>apps/nebula/lucide-react.d.ts (1)</summary> `1-3`: **Risk of shadowing upstream types / missing path** `lucide-react` already ships its own type declarations. Declaring the module again risks “Duplicate identifier” errors and may hide upstream improvements. Additionally, `"lucide-react/dist/lucide-react.suffixed"` is not part of the public package API and can disappear on minor upgrades. Unless you have a proven need to override the vendor types, consider deleting this file and relying on the official declarations instead. </details> <details> <summary>apps/nebula/src/app/(app)/data/examplePrompts.ts (1)</summary> `1-1`: ```shell #!/bin/bash # Re-run search for any import of ExamplePrompt in .ts and .tsx files rg -n "import .*ExamplePrompt" -g '*.ts' -g '*.tsx' || true # Also search for any standalone references to ExamplePrompt rg -n "ExamplePrompt" -g '*.ts' -g '*.tsx' || true
apps/nebula/src/app/(app)/components/ChatPageLayout.tsx (1)
33-36
: Nice move to absolute importsSwitching to alias-based paths improves readability and avoids brittle
../../..
chains.
No issues spotted in the functional code.apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx (1)
1-6
: Absolute-import switch looks goodThe move to the
@/
alias is consistent with the new structure and removes brittle relative paths.
Nothing else changed in these lines, so no further action required.apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx (1)
8-13
: Please double-check new relative pathsBoth
NebulaIcon
andCustomChatButton
paths changed significantly. Because this file sits four directories deep, it’s easy to overshoot the intended location.
Consider running a quickfd NebulaIcon
/fd CustomChatButton
to be sure the compiled build will still resolve these modules.#!/bin/bash # Verify the new imports exist fd NebulaIcon --full-path | head fd CustomChatButton --full-path | headapps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx (1)
3-11
: Import realignment LGTMThe switch to absolute aliases for configuration helpers (
nebulaAAOptions
,getSDKTheme
, etc.) matches the rest of the refactor and eliminates deep../../
chains.
No functional impact detected.apps/nebula/src/@/constants/nebula-client.ts (1)
14-16
: Consistent domain constants importMoving to
@/constants/urls
keeps all domain constants in one place and matches the alias convention. Implementation remains unchanged.
Good catch bringinggetVercelEnv
into the same block.apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx (1)
8-8
: ```shell
#!/bin/bashSearch for defineChain definitions and references in the monorepo
rg -A3 -n "defineChain" .
Search for getChain definitions and references in the monorepo
rg -A3 -n "getChain" .
</details> <details> <summary>apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts (1)</summary> `3-4`: **LGTM – canonical isomorphic layout-effect helper** The implementation follows the standard pattern and is concise. ✅ </details> <details> <summary>apps/nebula/src/app/(app)/components/ChatSidebar.tsx (1)</summary> `2-11`: **Import-path refactor looks correct** Absolute aliases improve readability and cut down on brittle relative paths. No issues spotted. </details> <details> <summary>apps/nebula/src/@/storybook/stubs.ts (1)</summary> `1-22`: **Avoid re-creating static data on every call** `loremWords` is re-allocated each time `randomLorem` is invoked. Hoisting the array to module scope removes this tiny but needless allocation and avoids polluting V8’s function-level hidden classes. ```diff -export function randomLorem(length: number) { - const loremWords = [ +const LOREM_WORDS = [ "lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing", "elit", "sed", "do", "eiusmod", "tempor", "incididunt", "ut", "labore", "et", "dolore", "magna", "aliqua", - ]; - - return Array.from({ length }, () => { - const randomIndex = Math.floor(Math.random() * loremWords.length); - return loremWords[randomIndex]; +]; + +export function randomLorem(length: number) { + return Array.from({ length }, () => { + const randomIndex = Math.floor(Math.random() * LOREM_WORDS.length); + return LOREM_WORDS[randomIndex]; }).join(" "); }
[ suggest_optional_refactor ]
apps/nebula/src/app/layout.tsx (1)
2-2
: Verify path to global stylesheet
"../global.css"
assumesapp/layout.tsx
sits insideapp/
, not deeper. If the file is relocated later the relative path breaks. Consider using an alias import (@/styles/global.css
) to remove this fragility.apps/nebula/src/@/config/sdk-component-theme.ts (1)
8-42
: Good abstraction of SDK theme overridesThe helper cleanly centralises colour-token mapping and keeps dark/light selection trivial.
Nice use ofThemeOverrides
– no issues spotted.apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx (1)
5-8
: Imports look good and match the new alias strategy.apps/nebula/src/app/move-funds/dashboard-client.ts (1)
20-32
: Production fallback silently differs from non-production – confirm this is intentional
setThirdwebDomains
runs only off-prod. If the default domains differ from the ones listed here, behaviour changes at deploy time.Consider extracting the domain map and using it in both environments, or at least documenting the divergence.
apps/nebula/next-sitemap.config.js (1)
10-16
: Robots policy may allow everything in preview deploymentsWhen
VERCEL_ENV !== "production"
the generated stanza is:User-agent: * Disallow: /move-funds
Because there is no blanket
Disallow: /
line, bots are free to crawl the rest of the site, which is usually not what you want for preview URLs.
If the intention is to block all in non-prod, explicitly add that rule.-allow: process.env.VERCEL_ENV === "production" ? ["/"] : [], -// disallow all if not production -disallow: ["/move-funds"], +allow: process.env.VERCEL_ENV === "production" ? ["/"] : [], +disallow: + process.env.VERCEL_ENV === "production" + ? ["/move-funds"] + : ["/"],apps/nebula/src/@/components/ui/switch.tsx (1)
12-25
: Component looks solid – no blocking issues detectedForward-ref, prop passthrough, and class-merge are correct. The Radix thumb is isolated from arbitrary props, which is fine for the common case.
apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css (1)
17-21
: Missing default value for custom property--shadow
The gradients rely on
var(--shadow)
but the variable is not defined in this module. Consider providing a sensible fallback or document where it is set.:root { --shadow: rgba(0 0 0 / 0.08); /* example fallback */ }apps/nebula/src/@/utils/vercel-utils.ts (1)
5-11
: Missing exhaustive env fallbacks & explicit return type
getVercelEnv()
omits the top-levelprocess.env.VERCEL_ENV
(not just the public one).- An explicit return type helps prevent future widening to plain
string
.-export function getVercelEnv() { +export function getVercelEnv(): "production" | "preview" | "development" { if (!isVercel()) { return "development"; } - return (process.env.VERCEL_ENV || + return ( + process.env.VERCEL_ENV || process.env.NEXT_PUBLIC_VERCEL_ENV || "production" ) as "production" | "preview" | "development"; }[ suggest_essential_refactor ]
apps/nebula/src/@/components/ui/code/RenderCode.tsx (1)
24-26
: Confirm HTML is trusted before usingdangerouslySetInnerHTML
Even with the ignore comment, ensure the HTML is either generated locally (as in
getCodeHtml
) or properly sanitised to prevent XSS when user-supplied code is rendered.apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx (1)
34-41
:Promise.all
change looks correctRemoving the Nebula call cleaned up the concurrent fetch array; no functional or perf regressions observed.
apps/nebula/src/@/components/ui/avatar.tsx (1)
8-20
: Avatar primitives look good
The wrapper cleanly forwards refs, merges classes, and exposes Radix display names. Nice, idiomatic composition.apps/nebula/src/@/components/ui/hover-card.tsx (1)
20-24
: LGTM – good Radix wrapper
Nothing blocking; the wrapper forwards refs & props correctly and applies sensible default animations.apps/nebula/src/@/components/ui/select.stories.tsx (1)
60-63
: Controlled component without change handler – React will warn
<Select value={...}>
makes the component controlled, but noonValueChange
is supplied, so selecting an item won’t update and React logs a warning.
UsedefaultValue
instead or wire anonValueChange
.-<Select value={props.selectFirst ? listItems[0] : undefined}> +<Select defaultValue={props.selectFirst ? listItems[0] : undefined}>apps/dashboard/src/components/CustomChat/types.ts (1)
10-13
: Mixedstring
vsnumber
chain identifiers
NebulaContext.chainIds
isstring[]
, buttransaction.chain_id
isnumber
. Align both to a single scalar type (string is safer for EVM hex ids), or add explicit conversion where you build messages.apps/nebula/src/@/components/ui/select.tsx (1)
15-34
: Looks solid – no actionable issues found.Forward-ref typing, variant prop and class-name handling are all correct, and you already expose Radix primitives directly for composability.
Nice job keeping the scroll buttons commented-out for later without polluting the bundle.apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx (1)
136-164
: Unused prop silently ignored inExternalApprovalNotice
.Even if you keep
initialFocusRef
, ignoring it inside the component is confusing for consumers and violates the declared prop contract. Either utilise it (e.g. pass toPopoverClose
or focus management) or remove it as suggested above.apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx (1)
118-139
:// @ts-expect-error
suppresses a real type mismatch – fix instead of silencing.Passing both
lang
andcode
as separate props should be modelled in the component’s type, eliminating the need for the directive and keeping the build clean.
621e452
to
caf0c0e
Compare
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.
Actionable comments posted: 4
♻️ Duplicate comments (2)
apps/nebula/src/@/constants/local-node.ts (1)
5-6
: Remove the hard-coded private key; load from an env var insteadThe secret is still committed verbatim despite earlier feedback. This violates basic secret-management hygiene, will keep triggering secret-scanners, and risks accidental mainnet usage.
Apply an env-var fallback (allowed only in non-production builds) and fail fast otherwise:
-export const LOCAL_NODE_PKEY = - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; +/** + * Private key for local-node testing. + * 1. Reads from NEXT_PUBLIC_LOCAL_NODE_PKEY when available + * 2. Falls back to Anvil’s well-known key ONLY outside production + */ +export const LOCAL_NODE_PKEY = + process.env.NEXT_PUBLIC_LOCAL_NODE_PKEY ?? + (process.env.NODE_ENV === "production" + ? (() => { + throw new Error("LOCAL_NODE_PKEY must be set in production"); + })() + : "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80");Also add
NEXT_PUBLIC_LOCAL_NODE_PKEY=
to your.env.local.example
so contributors know how to configure it.Need help wiring this through your build tooling or CI secret-scanners? Let me know.
apps/nebula/src/@/components/blocks/multi-select.tsx (1)
236-243
: Input is still not keyboard-focusable (tabIndex={-1}
)The past review already flagged this; the attribute is still present, so keyboard users cannot tab into the search box once the pop-over opens. Remove
tabIndex={-1}
and rely onautoFocus={false}
(or explicit focus management) to avoid unwanted mobile keyboards.
🧹 Nitpick comments (5)
apps/nebula/.env.example (2)
1-1
: Remove unnecessary quotes from environment variable values.In
.env
files, quoting is optional and can lead to parsing inconsistencies. Provide unquoted placeholder values in.env.example
to avoid confusion:- NEXT_PUBLIC_IPFS_GATEWAY_URL="https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path}" + NEXT_PUBLIC_IPFS_GATEWAY_URL=https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path}
2-2
: Remove unnecessary quotes from environment variable values.Apply the same unquoted style for the Nebula API URL:
- NEXT_PUBLIC_NEBULA_URL="https://nebula-api.thirdweb-dev.com" + NEXT_PUBLIC_NEBULA_URL=https://nebula-api.thirdweb-dev.comapps/dashboard/src/@/components/ui/skeleton.tsx (2)
24-31
:aria-hidden
hides all descendants – swap toaria-busy
While loading we want screen readers to ignore the placeholder but eventually announce the real content.
Becausearia-hidden="true"
is set on the outer wrapper, the loaded content remains hidden even afterisLoading
becomes false (the attribute is removed only on re-render, but users of virtual cursors may have already cached the subtree). Prefer signalling busy state instead:-aria-hidden={isLoading ? "true" : "false"} +aria-busy={isLoading}This keeps the node in the accessibility tree while correctly conveying the loading status.
22-23
: Treat bothnull
andundefined
as “not yet loaded”
isLoading
isprops.loadedData === undefined
; callers that legitimately returnnull
(common for “no result” states) will skip the skeleton and rendernull
, potentially violating layout expectations. Using loose equality covers both cases:-const isLoading = props.loadedData === undefined; +const isLoading = props.loadedData == null; // null or undefinedAlso applies to: 40-42
apps/nebula/src/@/components/blocks/multi-select.tsx (1)
118-147
: Consider replacing the manualfor
loop withfilter + slice
for clarityThe custom loop with
break
works, but the intent (“filter then take the first N”) is clearer and less error-prone with standard array helpers:-const filteredOptions: {label:string;value:string}[] = []; -const searchValLowercase = searchValue.toLowerCase(); -for (let i = 0; i <= options.length - 1; i++) { - if (filteredOptions.length >= itemsToShow) break; - const option = options[i]; - if (!option) continue; - const matches = overrideSearchFn - ? overrideSearchFn(option, searchValLowercase) - : option.label.toLowerCase().includes(searchValLowercase); - if (matches) filteredOptions.push(option); -} -return filteredOptions; +const searchValLower = searchValue.toLowerCase(); +return options + .filter((o) => + overrideSearchFn + ? overrideSearchFn(o, searchValLower) + : o.label.toLowerCase().includes(searchValLower), + ) + .slice(0, itemsToShow);Same complexity, shorter and easier to verify.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/nebula/src/app/opengraph-image.png
is excluded by!**/*.png
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (194)
apps/dashboard/.env.example
(0 hunks)apps/dashboard/package.json
(0 hunks)apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/client-only.tsx
(1 hunks)apps/dashboard/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/dashboard/src/@/components/ui/Spinner/Spinner.module.css
(0 hunks)apps/dashboard/src/@/components/ui/button.tsx
(1 hunks)apps/dashboard/src/@/components/ui/skeleton.tsx
(1 hunks)apps/dashboard/src/@/constants/public-envs.ts
(0 hunks)apps/dashboard/src/@/constants/server-envs.ts
(0 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/login/LoginPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx
(1 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
(0 hunks)apps/dashboard/src/app/nebula-app/layout.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/nebula-global.css
(0 hunks)apps/dashboard/src/app/nebula-app/readme.md
(0 hunks)apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
(0 hunks)apps/dashboard/src/components/CustomChat/ChatBar.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChatContent.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChats.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/types.ts
(1 hunks)apps/dashboard/src/components/explore/contract-card/index.tsx
(1 hunks)apps/dashboard/src/middleware.ts
(0 hunks)apps/dashboard/src/stories/stubs.ts
(0 hunks)apps/nebula/.env.example
(1 hunks)apps/nebula/.eslintignore
(1 hunks)apps/nebula/.eslintrc.js
(1 hunks)apps/nebula/.storybook/main.ts
(1 hunks)apps/nebula/.storybook/preview.tsx
(1 hunks)apps/nebula/LICENSE.md
(1 hunks)apps/nebula/README.md
(1 hunks)apps/nebula/biome.json
(1 hunks)apps/nebula/components.json
(1 hunks)apps/nebula/knip.json
(1 hunks)apps/nebula/lucide-react.d.ts
(1 hunks)apps/nebula/next-sitemap.config.js
(1 hunks)apps/nebula/next.config.ts
(1 hunks)apps/nebula/package.json
(1 hunks)apps/nebula/postcss.config.js
(1 hunks)apps/nebula/src/@/components/blocks/ChainIcon.tsx
(1 hunks)apps/nebula/src/@/components/blocks/FormFieldSetup.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MultiNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/NetworkSelectors.tsx
(1 hunks)apps/nebula/src/@/components/blocks/SingleNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/auto-connect.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/client-only.tsx
(2 hunks)apps/nebula/src/@/components/blocks/multi-select.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/multi-select.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.tsx
(1 hunks)apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx
(1 hunks)apps/nebula/src/@/components/blocks/wallet-address.tsx
(1 hunks)apps/nebula/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/nebula/src/@/components/ui/CopyTextButton.tsx
(1 hunks)apps/nebula/src/@/components/ui/DynamicHeight.tsx
(1 hunks)apps/nebula/src/@/components/ui/NavLink.tsx
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.module.css
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.tsx
(1 hunks)apps/nebula/src/@/components/ui/avatar.tsx
(1 hunks)apps/nebula/src/@/components/ui/badge.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/RenderCode.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.client.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/getCodeHtml.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/decimal-input.tsx
(1 hunks)apps/nebula/src/@/components/ui/dialog.tsx
(1 hunks)apps/nebula/src/@/components/ui/form.tsx
(1 hunks)apps/nebula/src/@/components/ui/hover-card.tsx
(1 hunks)apps/nebula/src/@/components/ui/inline-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/input.tsx
(1 hunks)apps/nebula/src/@/components/ui/label.tsx
(1 hunks)apps/nebula/src/@/components/ui/popover.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.tsx
(1 hunks)apps/nebula/src/@/components/ui/separator.tsx
(1 hunks)apps/nebula/src/@/components/ui/sheet.tsx
(1 hunks)apps/nebula/src/@/components/ui/skeleton.tsx
(1 hunks)apps/nebula/src/@/components/ui/sonner.tsx
(1 hunks)apps/nebula/src/@/components/ui/switch.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.tsx
(1 hunks)apps/nebula/src/@/components/ui/tabs.tsx
(1 hunks)apps/nebula/src/@/components/ui/text-shimmer.tsx
(1 hunks)apps/nebula/src/@/components/ui/textarea.tsx
(1 hunks)apps/nebula/src/@/components/ui/tooltip.tsx
(1 hunks)apps/nebula/src/@/config/sdk-component-theme.ts
(1 hunks)apps/nebula/src/@/constants/env-utils.ts
(1 hunks)apps/nebula/src/@/constants/local-node.ts
(1 hunks)apps/nebula/src/@/constants/nebula-client.ts
(1 hunks)apps/nebula/src/@/constants/public-envs.ts
(1 hunks)apps/nebula/src/@/constants/server-envs.ts
(1 hunks)apps/nebula/src/@/constants/urls.ts
(1 hunks)apps/nebula/src/@/data/eth-sanctioned-addresses.ts
(1 hunks)apps/nebula/src/@/hooks/chains.ts
(1 hunks)apps/nebula/src/@/hooks/use-clipboard.tsx
(1 hunks)apps/nebula/src/@/icons/NebulaIcon.tsx
(1 hunks)apps/nebula/src/@/lib/DashboardRouter.tsx
(1 hunks)apps/nebula/src/@/lib/reactive.ts
(1 hunks)apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts
(1 hunks)apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts
(1 hunks)apps/nebula/src/@/lib/useShowMore.ts
(1 hunks)apps/nebula/src/@/lib/utils.ts
(1 hunks)apps/nebula/src/@/storybook/stubs.ts
(1 hunks)apps/nebula/src/@/storybook/utils.tsx
(1 hunks)apps/nebula/src/@/types/chain.ts
(1 hunks)apps/nebula/src/@/utils/authToken.ts
(1 hunks)apps/nebula/src/@/utils/fetchChain.ts
(1 hunks)apps/nebula/src/@/utils/loginRedirect.ts
(1 hunks)apps/nebula/src/@/utils/map-chains.ts
(1 hunks)apps/nebula/src/@/utils/nebula-chains.ts
(1 hunks)apps/nebula/src/@/utils/parse-error.tsx
(1 hunks)apps/nebula/src/@/utils/vercel-utils.ts
(1 hunks)apps/nebula/src/@/utils/verifyTurnstileToken.ts
(1 hunks)apps/nebula/src/app/(app)/api/chat.ts
(1 hunks)apps/nebula/src/app/(app)/api/feedback.ts
(1 hunks)apps/nebula/src/app/(app)/api/session.ts
(1 hunks)apps/nebula/src/app/(app)/api/types.ts
(1 hunks)apps/nebula/src/app/(app)/chat/[session_id]/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/page.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatBar.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageContent.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatSidebar.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chatbar.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.tsx
(1 hunks)apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx
(2 hunks)apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx
(4 hunks)apps/nebula/src/app/(app)/components/Swap/common.tsx
(6 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/data/examplePrompts.ts
(2 hunks)apps/nebula/src/app/(app)/layout.tsx
(1 hunks)apps/nebula/src/app/(app)/page.tsx
(1 hunks)apps/nebula/src/app/(app)/utils/getChainIds.ts
(1 hunks)apps/nebula/src/app/layout.tsx
(1 hunks)apps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx
(1 hunks)apps/nebula/src/app/login/NebulaLoginPage.tsx
(1 hunks)apps/nebula/src/app/login/auth-actions.ts
(1 hunks)apps/nebula/src/app/login/page.tsx
(1 hunks)apps/nebula/src/app/move-funds/connect-button.tsx
(1 hunks)apps/nebula/src/app/move-funds/dashboard-client.ts
(1 hunks)apps/nebula/src/app/move-funds/move-funds.tsx
(4 hunks)apps/nebula/src/app/move-funds/page.tsx
(1 hunks)apps/nebula/src/app/not-found.tsx
(2 hunks)apps/nebula/src/app/page.tsx
(0 hunks)apps/nebula/src/app/providers.tsx
(2 hunks)apps/nebula/src/global.css
(1 hunks)apps/nebula/tailwind.config.js
(1 hunks)apps/nebula/tsconfig.json
(2 hunks)apps/nebula/vercel.json
(1 hunks)apps/playground-web/src/components/ui/Spinner/Spinner.module.css
(0 hunks)apps/portal/src/components/ui/Spinner/Spinner.module.css
(0 hunks)
💤 Files with no reviewable changes (17)
- apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
- apps/dashboard/package.json
- apps/portal/src/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/stories/stubs.ts
- apps/playground-web/src/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/@/constants/public-envs.ts
- apps/dashboard/src/@/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/app/nebula-app/readme.md
- apps/nebula/src/app/page.tsx
- apps/dashboard/src/app/nebula-app/nebula-global.css
- apps/dashboard/src/@/constants/server-envs.ts
- apps/dashboard/.env.example
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
- apps/dashboard/src/app/nebula-app/layout.tsx
- apps/dashboard/src/middleware.ts
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
✅ Files skipped from review due to trivial changes (5)
- apps/nebula/src/app/(app)/components/Chatbar.stories.tsx
- apps/nebula/vercel.json
- apps/nebula/src/app/move-funds/page.tsx
- apps/nebula/src/@/constants/urls.ts
- apps/nebula/src/@/components/blocks/NetworkSelectors.tsx
🚧 Files skipped from review as they are similar to previous changes (165)
- apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
- apps/dashboard/src/@/components/color-mode-toggle.tsx
- apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx
- apps/dashboard/src/@/components/Responsive.tsx
- apps/nebula/src/app/(app)/api/chat.ts
- apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx
- apps/nebula/README.md
- apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx
- apps/dashboard/src/components/CustomChat/CustomChats.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
- apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx
- apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx
- apps/nebula/src/app/(app)/components/Chats.stories.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
- apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx
- apps/dashboard/src/app/(app)/login/LoginPage.tsx
- apps/nebula/src/app/(app)/utils/getChainIds.ts
- apps/nebula/src/app/(app)/api/session.ts
- apps/nebula/src/app/(app)/api/feedback.ts
- apps/nebula/src/app/(app)/chat/history/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
- apps/nebula/src/app/login/NebulaLoginPage.tsx
- apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx
- apps/nebula/src/app/(app)/components/ChatBar.tsx
- apps/nebula/knip.json
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts
- apps/nebula/src/app/not-found.tsx
- apps/nebula/src/@/utils/authToken.ts
- apps/nebula/postcss.config.js
- apps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx
- apps/nebula/src/app/(app)/data/examplePrompts.ts
- apps/nebula/.eslintignore
- apps/nebula/.storybook/main.ts
- apps/nebula/biome.json
- apps/nebula/src/app/login/page.tsx
- apps/nebula/src/@/lib/utils.ts
- apps/nebula/src/app/(app)/api/types.ts
- apps/nebula/src/app/(app)/chat/[session_id]/page.tsx
- apps/nebula/lucide-react.d.ts
- apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts
- apps/nebula/src/app/move-funds/connect-button.tsx
- apps/nebula/src/app/(app)/layout.tsx
- apps/nebula/src/@/storybook/stubs.ts
- apps/nebula/src/@/constants/env-utils.ts
- apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx
- apps/nebula/src/@/constants/nebula-client.ts
- apps/nebula/src/@/components/blocks/auto-connect.tsx
- apps/nebula/src/@/components/ui/inline-code.tsx
- apps/nebula/src/app/(app)/components/ChatPageLayout.tsx
- apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
- apps/nebula/components.json
- apps/nebula/src/@/storybook/utils.tsx
- apps/nebula/src/app/(app)/components/ChatSidebar.tsx
- apps/nebula/src/app/move-funds/dashboard-client.ts
- apps/nebula/src/@/utils/loginRedirect.ts
- apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx
- apps/dashboard/src/components/explore/contract-card/index.tsx
- apps/nebula/src/@/components/ui/Spinner/Spinner.tsx
- apps/nebula/src/@/config/sdk-component-theme.ts
- apps/nebula/src/@/components/color-mode-toggle.tsx
- apps/nebula/src/@/components/ui/Spinner/Spinner.module.css
- apps/nebula/src/app/login/auth-actions.ts
- apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx
- apps/nebula/src/app/(app)/components/Swap/common.tsx
- apps/nebula/package.json
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
- apps/nebula/src/app/(app)/components/Chats.tsx
- apps/nebula/src/app/(app)/page.tsx
- apps/nebula/src/app/providers.tsx
- apps/nebula/src/@/components/blocks/MultiNetworkSelector.stories.tsx
- apps/nebula/src/@/constants/server-envs.ts
- apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css
- apps/nebula/src/@/components/ui/sonner.tsx
- apps/nebula/src/app/move-funds/move-funds.tsx
- apps/nebula/src/@/hooks/use-clipboard.tsx
- apps/nebula/src/@/icons/NebulaIcon.tsx
- apps/nebula/src/@/utils/verifyTurnstileToken.ts
- apps/nebula/src/@/data/eth-sanctioned-addresses.ts
- apps/nebula/src/@/components/ui/avatar.tsx
- apps/nebula/src/@/components/ui/label.tsx
- apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
- apps/nebula/src/@/utils/map-chains.ts
- apps/nebula/src/@/components/ui/input.tsx
- apps/nebula/tsconfig.json
- apps/nebula/src/@/utils/fetchChain.ts
- apps/nebula/src/@/utils/nebula-chains.ts
- apps/nebula/src/@/components/ui/code/getCodeHtml.tsx
- apps/nebula/src/@/components/ui/text-shimmer.tsx
- apps/nebula/src/@/components/ui/DynamicHeight.tsx
- apps/nebula/src/@/components/ui/separator.tsx
- apps/nebula/src/@/hooks/chains.ts
- apps/nebula/src/app/(app)/components/ChatPageContent.tsx
- apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts
- apps/nebula/src/@/utils/vercel-utils.ts
- apps/nebula/next-sitemap.config.js
- apps/nebula/src/@/components/ui/popover.tsx
- apps/nebula/src/@/constants/public-envs.ts
- apps/nebula/src/@/components/blocks/client-only.tsx
- apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx
- apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx
- apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx
- apps/nebula/next.config.ts
- apps/nebula/src/@/components/ui/code/RenderCode.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx
- apps/dashboard/src/components/CustomChat/ChatBar.tsx
- apps/nebula/src/@/components/ui/code/plaintext-code.tsx
- apps/nebula/src/@/components/blocks/select-with-search.stories.tsx
- apps/nebula/src/@/components/blocks/multi-select.stories.tsx
- apps/nebula/src/@/components/ui/sheet.tsx
- apps/nebula/src/@/components/ui/code/code.client.tsx
- apps/nebula/src/@/components/blocks/FormFieldSetup.tsx
- apps/nebula/.eslintrc.js
- apps/nebula/src/@/components/blocks/Img.stories.tsx
- apps/nebula/src/@/components/ui/switch.tsx
- apps/nebula/src/@/components/ui/code/code.stories.tsx
- apps/dashboard/src/components/CustomChat/CustomChatContent.tsx
- apps/nebula/src/@/components/ui/textarea.tsx
- apps/nebula/src/@/lib/useShowMore.ts
- apps/nebula/src/@/components/ui/badge.tsx
- apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx
- apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx
- apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx
- apps/nebula/src/@/components/ui/button.tsx
- apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx
- apps/nebula/src/@/components/blocks/select-with-search.tsx
- apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx
- apps/nebula/src/@/components/blocks/ChainIcon.tsx
- apps/nebula/src/@/utils/parse-error.tsx
- apps/nebula/src/@/components/ui/select.stories.tsx
- apps/nebula/src/app/(app)/chat/page.tsx
- apps/dashboard/src/@/components/blocks/client-only.tsx
- apps/nebula/tailwind.config.js
- apps/nebula/src/@/components/ui/button.stories.tsx
- apps/nebula/src/@/components/blocks/Img.tsx
- apps/nebula/src/global.css
- apps/nebula/src/app/layout.tsx
- apps/nebula/src/@/lib/reactive.ts
- apps/nebula/src/@/components/ui/hover-card.tsx
- apps/nebula/src/@/types/chain.ts
- apps/nebula/src/@/components/ui/table.stories.tsx
- apps/dashboard/src/components/CustomChat/types.ts
- apps/nebula/src/@/components/blocks/SingleNetworkSelector.stories.tsx
- apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx
- apps/nebula/src/@/components/ui/skeleton.tsx
- apps/nebula/.storybook/preview.tsx
- apps/nebula/src/@/components/ui/decimal-input.tsx
- apps/nebula/src/@/lib/DashboardRouter.tsx
- apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx
- apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx
- apps/nebula/src/@/components/ui/table.tsx
- apps/nebula/src/@/components/ui/dialog.tsx
- apps/nebula/src/@/components/ui/NavLink.tsx
- apps/nebula/src/@/components/ui/tooltip.tsx
- apps/nebula/src/@/components/ui/select.tsx
- apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx
- apps/nebula/src/@/components/blocks/buttons/TransactionButton.stories.tsx
- apps/nebula/src/@/components/ui/form.tsx
- apps/nebula/src/@/components/ui/CopyTextButton.tsx
- apps/nebula/src/@/components/blocks/wallet-address.tsx
🧰 Additional context used
🪛 dotenv-linter (3.3.0)
apps/nebula/.env.example
[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
🪛 LanguageTool
apps/nebula/LICENSE.md
[uncategorized] ~150-~150: Possible missing comma found.
Context: ...iateness of using or redistributing the Work and assume any risks associated wit...
(AI_HYDRA_LEO_MISSING_COMMA)
[style] ~161-~161: ‘any and all’ might be wordy. Consider a shorter alternative.
Context: ...ge, computer failure or malfunction, or any and all other commercial damages or losses)...
(EN_WORDINESS_PREMIUM_ANY_AND_ALL)
🪛 Gitleaks (8.26.0)
apps/nebula/src/@/constants/local-node.ts
5-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🔇 Additional comments (5)
apps/nebula/LICENSE.md (2)
1-202
: Add Apache 2.0 license for Nebula app.
The complete Apache License, Version 2.0 text has been added verbatim and looks correct. Ensure this file is placed at the root of theapps/nebula
directory so the licensing is clearly applied to the new standalone Nebula app.
189-190
: Verify copyright year and holder.
Please confirm thatCopyright 2021 Non-Fungible Labs, Inc
is intentional for this project.
If the Nebula app is being released under a different organization or year, update this field accordingly.apps/dashboard/src/@/components/ui/button.tsx (1)
12-21
: Double-check typography weight after droppingtext-semibold
.
font-medium
remains in the base class list, so these variants now render at weight 500 instead of 600.
If that change was intentional to align with the new design system, all good. Otherwise, text in primary / destructive / outline / secondary / ghost / link buttons will appear lighter than before.Please confirm with design or run a quick visual regression to ensure the new weight still meets accessibility & brand-consistency requirements.
apps/nebula/src/@/components/ui/tabs.tsx (1)
1-210
: Overall component structure looks solid.Clean separation between
TabLinks
,TabButtons
, anduseUnderline
, good use ofResizeObserver
, and thoughtful class-name overrides.apps/dashboard/src/@/components/ui/skeleton.tsx (1)
15-21
: Let’s enumerate allSkeletonContainer
usages in TSX and specifically look for any with a two-argrender
prop:#!/bin/bash # 1. List all SkeletonContainer usages with context rg --no-heading -n '<SkeletonContainer' -g '*.tsx' -A3 # 2. Narrow down to any render props taking two parameters rg --no-heading -n '<SkeletonContainer[^>]*render=\{\s*\([^,]+,\s*[^)]+\)' -g '*.tsx'
0a73e5b
to
2ae8de4
Compare
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.
Actionable comments posted: 0
♻️ Duplicate comments (4)
apps/nebula/src/@/constants/local-node.ts (1)
5-6
: Hard-coded private key still present – move to env var immediatelyPrevious review already flagged this secret (see past comments). Keeping it in VCS violates basic secret-management hygiene and continues to trigger scanners.
Proposed quick fix:
-export const LOCAL_NODE_PKEY = - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; +export const LOCAL_NODE_PKEY = + process.env.NEXT_PUBLIC_LOCAL_NODE_PKEY ?? + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; // fallback for local dev onlyAlso add
NEXT_PUBLIC_LOCAL_NODE_PKEY=
to.env.example
and scrub the committed secret from history if possible.apps/nebula/src/@/components/ui/tabs.tsx (3)
49-66
: Disabled<Link>
is still keyboard-focusable – add proper inert semantics or render a non-interactive element.
pointer-events-none
blocks the mouse, but the anchor remains in the tab order so keyboard users can still focus and “activate” it (and screen-readers will announce it as an enabled link). Either:
- Render a
<span>
whentab.isDisabled
is true, or- Keep the
<Link>
but drop it from the tab order and clear thehref
.<Link data-active={tab.isActive} ref={tab.isActive ? activeTabRef : undefined} - href={tab.href} - aria-disabled={tab.isDisabled} + href={tab.isDisabled ? undefined : tab.href} + aria-disabled={tab.isDisabled} + tabIndex={tab.isDisabled ? -1 : 0} className={cn(This is the same accessibility issue raised in a previous review and is still unresolved.
170-180
: Underline drift persists when the tab row is horizontally scrolled.The translateX calculation still ignores
containerRef.current.scrollLeft
, so the active-line will be offset once the user scrolls the tab list.- lineEl.style.transform = `translateX(${rect.left - containerPaddingLeft}px)`; + const scrollLeft = containerRef.current.scrollLeft; + lineEl.style.transform = `translateX(${rect.left - containerPaddingLeft + (activeTabEl.offsetLeft - scrollLeft)}px)`;Same issue was highlighted earlier; please adjust or rewrite using
offsetLeft
/offsetWidth
to avoidgetBoundingClientRect
math.
125-136
:TabButtons
: missingdisabled
attribute leaves “disabled” buttons operable & focus-able.Only stripping the
onClick
handler + styling (cursor-not-allowed opacity-50
) isn’t sufficient. For complete accessibility you must set the actualdisabled
prop so the element is removed from the tab order and announces as disabled.<Button variant="ghost" ref={tab.isActive ? activeTabRef : undefined} + disabled={tab.isDisabled} className={cn(
With this change, you can drop the manual
cursor-not-allowed
style because ShadCN/ Radix’s disabled state already covers it.
🧹 Nitpick comments (2)
apps/nebula/.env.example (1)
1-2
: Remove quotes from environment variable values
Quoted values may be included literally by some dotenv parsers and trigger linter warnings. Unquoted assignments ensure the values are parsed correctly and satisfy dotenv-linter rules.- NEXT_PUBLIC_IPFS_GATEWAY_URL="https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path}" + NEXT_PUBLIC_IPFS_GATEWAY_URL=https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path} - NEXT_PUBLIC_NEBULA_URL="https://nebula-api.thirdweb-dev.com" + NEXT_PUBLIC_NEBULA_URL=https://nebula-api.thirdweb-dev.comapps/nebula/src/@/components/ui/tabs.tsx (1)
192-199
: Underline does not update on user scroll – addscroll
listener.
ResizeObserver
handles dimension changes, but if the user scrolls the tab list (e.g., with a mouse wheel),update()
is never called and the underline desynchronises. Attach ascroll
event listener tocontainerRef.current
.if (containerRef.current) { resizeObserver = new ResizeObserver(() => { … }); resizeObserver.observe(containerRef.current); + + // keep underline in sync while user scrolls horizontally + containerRef.current.addEventListener("scroll", update, { passive: true }); } … return () => { … + containerRef.current?.removeEventListener("scroll", update); };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/nebula/src/app/opengraph-image.png
is excluded by!**/*.png
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (194)
apps/dashboard/.env.example
(0 hunks)apps/dashboard/package.json
(0 hunks)apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/client-only.tsx
(1 hunks)apps/dashboard/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/dashboard/src/@/components/ui/Spinner/Spinner.module.css
(0 hunks)apps/dashboard/src/@/components/ui/button.tsx
(1 hunks)apps/dashboard/src/@/components/ui/skeleton.tsx
(1 hunks)apps/dashboard/src/@/constants/public-envs.ts
(0 hunks)apps/dashboard/src/@/constants/server-envs.ts
(0 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/login/LoginPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx
(1 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
(0 hunks)apps/dashboard/src/app/nebula-app/layout.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/nebula-global.css
(0 hunks)apps/dashboard/src/app/nebula-app/readme.md
(0 hunks)apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
(0 hunks)apps/dashboard/src/components/CustomChat/ChatBar.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChatContent.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChats.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/types.ts
(1 hunks)apps/dashboard/src/components/explore/contract-card/index.tsx
(1 hunks)apps/dashboard/src/middleware.ts
(0 hunks)apps/dashboard/src/stories/stubs.ts
(0 hunks)apps/nebula/.env.example
(1 hunks)apps/nebula/.eslintignore
(1 hunks)apps/nebula/.eslintrc.js
(1 hunks)apps/nebula/.storybook/main.ts
(1 hunks)apps/nebula/.storybook/preview.tsx
(1 hunks)apps/nebula/LICENSE.md
(1 hunks)apps/nebula/README.md
(1 hunks)apps/nebula/biome.json
(1 hunks)apps/nebula/components.json
(1 hunks)apps/nebula/knip.json
(1 hunks)apps/nebula/lucide-react.d.ts
(1 hunks)apps/nebula/next-sitemap.config.js
(1 hunks)apps/nebula/next.config.ts
(1 hunks)apps/nebula/package.json
(1 hunks)apps/nebula/postcss.config.js
(1 hunks)apps/nebula/src/@/components/blocks/ChainIcon.tsx
(1 hunks)apps/nebula/src/@/components/blocks/FormFieldSetup.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MultiNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/NetworkSelectors.tsx
(1 hunks)apps/nebula/src/@/components/blocks/SingleNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/auto-connect.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/client-only.tsx
(2 hunks)apps/nebula/src/@/components/blocks/multi-select.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/multi-select.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.tsx
(1 hunks)apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx
(1 hunks)apps/nebula/src/@/components/blocks/wallet-address.tsx
(1 hunks)apps/nebula/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/nebula/src/@/components/ui/CopyTextButton.tsx
(1 hunks)apps/nebula/src/@/components/ui/DynamicHeight.tsx
(1 hunks)apps/nebula/src/@/components/ui/NavLink.tsx
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.module.css
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.tsx
(1 hunks)apps/nebula/src/@/components/ui/avatar.tsx
(1 hunks)apps/nebula/src/@/components/ui/badge.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/RenderCode.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.client.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/getCodeHtml.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/decimal-input.tsx
(1 hunks)apps/nebula/src/@/components/ui/dialog.tsx
(1 hunks)apps/nebula/src/@/components/ui/form.tsx
(1 hunks)apps/nebula/src/@/components/ui/hover-card.tsx
(1 hunks)apps/nebula/src/@/components/ui/inline-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/input.tsx
(1 hunks)apps/nebula/src/@/components/ui/label.tsx
(1 hunks)apps/nebula/src/@/components/ui/popover.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.tsx
(1 hunks)apps/nebula/src/@/components/ui/separator.tsx
(1 hunks)apps/nebula/src/@/components/ui/sheet.tsx
(1 hunks)apps/nebula/src/@/components/ui/skeleton.tsx
(1 hunks)apps/nebula/src/@/components/ui/sonner.tsx
(1 hunks)apps/nebula/src/@/components/ui/switch.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.tsx
(1 hunks)apps/nebula/src/@/components/ui/tabs.tsx
(1 hunks)apps/nebula/src/@/components/ui/text-shimmer.tsx
(1 hunks)apps/nebula/src/@/components/ui/textarea.tsx
(1 hunks)apps/nebula/src/@/components/ui/tooltip.tsx
(1 hunks)apps/nebula/src/@/config/sdk-component-theme.ts
(1 hunks)apps/nebula/src/@/constants/env-utils.ts
(1 hunks)apps/nebula/src/@/constants/local-node.ts
(1 hunks)apps/nebula/src/@/constants/nebula-client.ts
(1 hunks)apps/nebula/src/@/constants/public-envs.ts
(1 hunks)apps/nebula/src/@/constants/server-envs.ts
(1 hunks)apps/nebula/src/@/constants/urls.ts
(1 hunks)apps/nebula/src/@/data/eth-sanctioned-addresses.ts
(1 hunks)apps/nebula/src/@/hooks/chains.ts
(1 hunks)apps/nebula/src/@/hooks/use-clipboard.tsx
(1 hunks)apps/nebula/src/@/icons/NebulaIcon.tsx
(1 hunks)apps/nebula/src/@/lib/DashboardRouter.tsx
(1 hunks)apps/nebula/src/@/lib/reactive.ts
(1 hunks)apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts
(1 hunks)apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts
(1 hunks)apps/nebula/src/@/lib/useShowMore.ts
(1 hunks)apps/nebula/src/@/lib/utils.ts
(1 hunks)apps/nebula/src/@/storybook/stubs.ts
(1 hunks)apps/nebula/src/@/storybook/utils.tsx
(1 hunks)apps/nebula/src/@/types/chain.ts
(1 hunks)apps/nebula/src/@/utils/authToken.ts
(1 hunks)apps/nebula/src/@/utils/fetchChain.ts
(1 hunks)apps/nebula/src/@/utils/loginRedirect.ts
(1 hunks)apps/nebula/src/@/utils/map-chains.ts
(1 hunks)apps/nebula/src/@/utils/nebula-chains.ts
(1 hunks)apps/nebula/src/@/utils/parse-error.tsx
(1 hunks)apps/nebula/src/@/utils/vercel-utils.ts
(1 hunks)apps/nebula/src/@/utils/verifyTurnstileToken.ts
(1 hunks)apps/nebula/src/app/(app)/api/chat.ts
(1 hunks)apps/nebula/src/app/(app)/api/feedback.ts
(1 hunks)apps/nebula/src/app/(app)/api/session.ts
(1 hunks)apps/nebula/src/app/(app)/api/types.ts
(1 hunks)apps/nebula/src/app/(app)/chat/[session_id]/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/page.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatBar.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageContent.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatSidebar.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chatbar.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.tsx
(1 hunks)apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx
(2 hunks)apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx
(4 hunks)apps/nebula/src/app/(app)/components/Swap/common.tsx
(6 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/data/examplePrompts.ts
(2 hunks)apps/nebula/src/app/(app)/layout.tsx
(1 hunks)apps/nebula/src/app/(app)/page.tsx
(1 hunks)apps/nebula/src/app/(app)/utils/getChainIds.ts
(1 hunks)apps/nebula/src/app/layout.tsx
(1 hunks)apps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx
(1 hunks)apps/nebula/src/app/login/NebulaLoginPage.tsx
(1 hunks)apps/nebula/src/app/login/auth-actions.ts
(1 hunks)apps/nebula/src/app/login/page.tsx
(1 hunks)apps/nebula/src/app/move-funds/connect-button.tsx
(1 hunks)apps/nebula/src/app/move-funds/dashboard-client.ts
(1 hunks)apps/nebula/src/app/move-funds/move-funds.tsx
(4 hunks)apps/nebula/src/app/move-funds/page.tsx
(1 hunks)apps/nebula/src/app/not-found.tsx
(2 hunks)apps/nebula/src/app/page.tsx
(0 hunks)apps/nebula/src/app/providers.tsx
(2 hunks)apps/nebula/src/global.css
(1 hunks)apps/nebula/tailwind.config.js
(1 hunks)apps/nebula/tsconfig.json
(2 hunks)apps/nebula/vercel.json
(1 hunks)apps/playground-web/src/components/ui/Spinner/Spinner.module.css
(0 hunks)apps/portal/src/components/ui/Spinner/Spinner.module.css
(0 hunks)
💤 Files with no reviewable changes (17)
- apps/dashboard/src/stories/stubs.ts
- apps/dashboard/package.json
- apps/dashboard/src/@/constants/public-envs.ts
- apps/dashboard/src/@/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
- apps/portal/src/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/app/nebula-app/nebula-global.css
- apps/dashboard/src/@/constants/server-envs.ts
- apps/nebula/src/app/page.tsx
- apps/playground-web/src/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/middleware.ts
- apps/dashboard/.env.example
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
- apps/dashboard/src/app/nebula-app/layout.tsx
- apps/dashboard/src/app/nebula-app/readme.md
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
✅ Files skipped from review due to trivial changes (6)
- apps/nebula/src/app/(app)/components/Chatbar.stories.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
- apps/nebula/src/@/utils/authToken.ts
- apps/nebula/src/@/constants/urls.ts
- apps/nebula/src/@/components/ui/table.stories.tsx
- apps/nebula/src/@/utils/parse-error.tsx
🚧 Files skipped from review as they are similar to previous changes (167)
- apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
- apps/nebula/README.md
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx
- apps/dashboard/src/app/(app)/login/LoginPage.tsx
- apps/dashboard/src/@/components/Responsive.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts
- apps/nebula/biome.json
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx
- apps/nebula/src/app/(app)/api/chat.ts
- apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx
- apps/nebula/postcss.config.js
- apps/dashboard/src/@/components/color-mode-toggle.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx
- apps/nebula/src/app/(app)/utils/getChainIds.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
- apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx
- apps/dashboard/src/components/explore/contract-card/index.tsx
- apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
- apps/dashboard/src/components/CustomChat/CustomChats.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx
- apps/nebula/src/app/move-funds/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx
- apps/nebula/src/app/(app)/api/feedback.ts
- apps/nebula/src/app/(app)/components/Chats.stories.tsx
- apps/nebula/src/app/login/NebulaLoginPage.tsx
- apps/nebula/src/app/(app)/chat/history/page.tsx
- apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx
- apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx
- apps/nebula/knip.json
- apps/nebula/.eslintignore
- apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx
- apps/nebula/src/app/not-found.tsx
- apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx
- apps/nebula/vercel.json
- apps/nebula/src/app/(app)/layout.tsx
- apps/nebula/src/@/components/color-mode-toggle.tsx
- apps/nebula/lucide-react.d.ts
- apps/dashboard/src/@/components/ui/button.tsx
- apps/nebula/src/app/(app)/api/session.ts
- apps/nebula/src/@/storybook/stubs.ts
- apps/nebula/src/@/components/ui/inline-code.tsx
- apps/nebula/src/app/(app)/components/ChatPageLayout.tsx
- apps/nebula/src/app/(app)/api/types.ts
- apps/nebula/src/@/components/ui/Spinner/Spinner.tsx
- apps/nebula/src/@/components/ui/Spinner/Spinner.module.css
- apps/nebula/src/app/(app)/data/examplePrompts.ts
- apps/nebula/src/app/(app)/components/ChatBar.tsx
- apps/nebula/src/@/lib/utils.ts
- apps/nebula/src/@/constants/env-utils.ts
- apps/nebula/components.json
- apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx
- apps/nebula/src/@/components/ui/label.tsx
- apps/nebula/src/@/constants/nebula-client.ts
- apps/nebula/src/app/(app)/chat/[session_id]/page.tsx
- apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
- apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx
- apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx
- apps/nebula/src/@/utils/nebula-chains.ts
- apps/nebula/src/@/components/blocks/FormFieldSetup.tsx
- apps/nebula/src/app/login/page.tsx
- apps/nebula/src/@/utils/loginRedirect.ts
- apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx
- apps/nebula/src/app/move-funds/connect-button.tsx
- apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts
- apps/dashboard/src/@/components/ui/skeleton.tsx
- apps/nebula/src/@/components/ui/code/getCodeHtml.tsx
- apps/nebula/src/@/components/blocks/auto-connect.tsx
- apps/nebula/src/@/components/ui/sonner.tsx
- apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx
- apps/nebula/src/@/data/eth-sanctioned-addresses.ts
- apps/nebula/src/@/components/ui/DynamicHeight.tsx
- apps/nebula/src/@/config/sdk-component-theme.ts
- apps/nebula/src/@/utils/verifyTurnstileToken.ts
- apps/nebula/src/app/(app)/chat/page.tsx
- apps/nebula/src/app/(app)/components/Chats.tsx
- apps/nebula/src/@/storybook/utils.tsx
- apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx
- apps/nebula/src/@/components/ui/separator.tsx
- apps/nebula/.storybook/main.ts
- apps/nebula/src/@/utils/fetchChain.ts
- apps/nebula/src/@/components/ui/text-shimmer.tsx
- apps/nebula/src/app/(app)/page.tsx
- apps/nebula/next.config.ts
- apps/nebula/src/app/(app)/components/ChatSidebar.tsx
- apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css
- apps/nebula/src/app/providers.tsx
- apps/nebula/src/@/components/ui/input.tsx
- apps/nebula/src/@/components/ui/popover.tsx
- apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts
- apps/nebula/src/app/(app)/components/ChatPageContent.tsx
- apps/nebula/src/@/utils/map-chains.ts
- apps/nebula/src/app/move-funds/move-funds.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
- apps/nebula/src/@/components/ui/switch.tsx
- apps/nebula/src/@/icons/NebulaIcon.tsx
- apps/nebula/src/app/move-funds/dashboard-client.ts
- apps/nebula/src/@/hooks/use-clipboard.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
- apps/nebula/src/@/constants/public-envs.ts
- apps/nebula/src/@/hooks/chains.ts
- apps/nebula/package.json
- apps/nebula/next-sitemap.config.js
- apps/nebula/src/app/login/auth-actions.ts
- apps/dashboard/src/components/CustomChat/ChatBar.tsx
- apps/nebula/src/@/components/ui/avatar.tsx
- apps/nebula/src/@/constants/server-envs.ts
- apps/nebula/src/app/(app)/components/Swap/common.tsx
- apps/nebula/src/@/components/ui/code/code.client.tsx
- apps/nebula/src/@/components/ui/code/code.stories.tsx
- apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx
- apps/dashboard/src/@/components/blocks/client-only.tsx
- apps/nebula/src/@/components/ui/code/plaintext-code.tsx
- apps/nebula/src/@/components/ui/sheet.tsx
- apps/nebula/src/@/components/blocks/MultiNetworkSelector.stories.tsx
- apps/nebula/src/@/components/blocks/multi-select.stories.tsx
- apps/nebula/src/@/components/blocks/select-with-search.stories.tsx
- apps/nebula/src/@/components/ui/select.stories.tsx
- apps/nebula/src/@/components/blocks/Img.tsx
- apps/nebula/src/@/components/ui/textarea.tsx
- apps/nebula/src/@/components/ui/badge.tsx
- apps/nebula/src/@/components/ui/code/RenderCode.tsx
- apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx
- apps/nebula/src/@/types/chain.ts
- apps/nebula/src/@/components/ui/skeleton.tsx
- apps/nebula/src/@/components/ui/dialog.tsx
- apps/nebula/src/@/components/blocks/select-with-search.tsx
- apps/nebula/src/@/components/ui/button.stories.tsx
- apps/nebula/src/@/components/ui/button.tsx
- apps/nebula/src/@/components/ui/CopyTextButton.tsx
- apps/nebula/tsconfig.json
- apps/nebula/src/app/layout.tsx
- apps/nebula/src/@/utils/vercel-utils.ts
- apps/nebula/src/@/components/blocks/client-only.tsx
- apps/nebula/.eslintrc.js
- apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx
- apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx
- apps/nebula/src/@/components/ui/decimal-input.tsx
- apps/nebula/src/@/components/ui/hover-card.tsx
- apps/nebula/src/@/components/blocks/Img.stories.tsx
- apps/nebula/.storybook/preview.tsx
- apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx
- apps/nebula/src/@/lib/reactive.ts
- apps/nebula/src/@/lib/useShowMore.ts
- apps/nebula/src/@/lib/DashboardRouter.tsx
- apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx
- apps/dashboard/src/components/CustomChat/types.ts
- apps/nebula/tailwind.config.js
- apps/nebula/src/global.css
- apps/nebula/src/@/components/blocks/multi-select.tsx
- apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx
- apps/nebula/src/@/components/ui/table.tsx
- apps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx
- apps/nebula/src/@/components/ui/NavLink.tsx
- apps/dashboard/src/components/CustomChat/CustomChatContent.tsx
- apps/nebula/src/@/components/ui/tooltip.tsx
- apps/nebula/src/@/components/ui/select.tsx
- apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx
- apps/nebula/src/@/components/blocks/ChainIcon.tsx
- apps/nebula/src/@/components/blocks/wallet-address.tsx
- apps/nebula/src/@/components/blocks/buttons/TransactionButton.stories.tsx
- apps/nebula/src/@/components/ui/form.tsx
- apps/nebula/src/@/components/blocks/NetworkSelectors.tsx
- apps/nebula/src/@/components/blocks/SingleNetworkSelector.stories.tsx
- apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx
🧰 Additional context used
🪛 dotenv-linter (3.3.0)
apps/nebula/.env.example
[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
🪛 LanguageTool
apps/nebula/LICENSE.md
[uncategorized] ~150-~150: Possible missing comma found.
Context: ...iateness of using or redistributing the Work and assume any risks associated wit...
(AI_HYDRA_LEO_MISSING_COMMA)
[style] ~161-~161: ‘any and all’ might be wordy. Consider a shorter alternative.
Context: ...ge, computer failure or malfunction, or any and all other commercial damages or losses)...
(EN_WORDINESS_PREMIUM_ANY_AND_ALL)
🪛 Gitleaks (8.26.0)
apps/nebula/src/@/constants/local-node.ts
5-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, webpack)
- GitHub Check: Unit Tests
- GitHub Check: Lint Packages
- GitHub Check: Build Packages
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/nebula/LICENSE.md (2)
1-202
: Add standard Apache License v2.0
The file includes the unmodified Apache License, Version 2.0. Ensure this aligns with your intended licensing and project policy for the standalone Nebula app.
189-191
: Verify copyright holder and year
The notice states “Copyright 2021 Non-Fungible Labs, Inc.”. Please confirm that this reflects the correct entity name and the applicable year for theapps/nebula
project.
2ae8de4
to
31b60cc
Compare
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.
Actionable comments posted: 1
♻️ Duplicate comments (4)
apps/nebula/src/@/constants/local-node.ts (1)
5-6
: Remove hard-coded private key – load from env insteadA private key in VCS is a hard no: it teaches bad practice, trips secret-scanners, and can be mis-used on the wrong network. Load it from an env variable and fall back only in dev when
NODE_ENV !== "production"
.-export const LOCAL_NODE_PKEY = - "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; +export const LOCAL_NODE_PKEY = + process.env.NEXT_PUBLIC_LOCAL_NODE_PKEY ?? + (process.env.NODE_ENV === "production" + ? (() => { + throw new Error("LOCAL_NODE_PKEY not configured"); + })() + : "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80");Also add the key to an example
.env.local.example
file and git-ignore any real.env.local
.apps/nebula/src/@/components/ui/tabs.tsx (3)
49-66
: DisabledLink
is still keyboard-focusable – drop it from the tab-orderPassing
disabled
to<Button asChild>
does not affect the inner<a>
element, andpointer-events-none
only prevents mouse clicks. The anchor can still be reached with Tab/Shift-Tab, violating accessibility expectations for a disabled control.
Either render a non-interactive element (<span>
) whentab.isDisabled
is true, or explicitly settabIndex={-1}
on the anchor.-<Link +<Link data-active={tab.isActive} ref={tab.isActive ? activeTabRef : undefined} href={tab.href} aria-disabled={tab.isDisabled} + tabIndex={tab.isDisabled ? -1 : 0} className={cn(
125-137
:TabButtons
: missingdisabled
attribute leaves buttons interactive
onClick
is removed whentab.isDisabled
, but the element is still focusable and will fire unintended events if the consumer attaches key handlers. Use the nativedisabled
attribute so the browser handles focus management and ARIA automatically.-<Button - variant="ghost" - ref={tab.isActive ? activeTabRef : undefined} +<Button + variant="ghost" + ref={tab.isActive ? activeTabRef : undefined} + disabled={tab.isDisabled} className={cn(
171-180
: Underline drifts when the tab list is horizontally scrolled
translateX
is calculated fromrect.left
relative to the viewport, ignoring the horizontal scroll offset ofcontainerRef
. When the tab row is scrolled, the underline no longer sits under the active tab.- lineEl.style.transform = `translateX(${ - rect.left - containerPaddingLeft - }px)`; + const scrollLeft = containerRef.current.scrollLeft; + lineEl.style.transform = `translateX(${ + rect.left - containerPaddingLeft + (activeTabEl.offsetLeft - scrollLeft) + }px)`;Alternatively, drop
getBoundingClientRect()
and rely onoffsetLeft/offsetWidth
for simpler, scroll-aware math.
🧹 Nitpick comments (4)
apps/nebula/.env.example (2)
1-1
: Remove unnecessary quotes around IPFS gateway URL
dotenv-linter flags quote characters here. Since the URL contains no spaces or special shell characters, you can omit the quotes to satisfy linting and keep the example file clean.
Use this diff to update the line:-NEXT_PUBLIC_IPFS_GATEWAY_URL="https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path}" +NEXT_PUBLIC_IPFS_GATEWAY_URL=https://{clientId}.thirdwebstorage-dev.com/ipfs/{cid}/{path}
2-2
: Remove unnecessary quotes around Nebula API URL
For consistency and to address the same lint warning, drop the quotes here as well.
Apply this diff:-NEXT_PUBLIC_NEBULA_URL="https://nebula-api.thirdweb-dev.com" +NEXT_PUBLIC_NEBULA_URL=https://nebula-api.thirdweb-dev.comapps/nebula/src/app/layout.tsx (2)
14-21
: Addicons
to the Next 13metadata
object instead of a manual<link>
Next.js will automatically inject<link rel="icon">
tags when you specify:export const metadata = { icons: { icon: "/assets/nebula/favicon.ico", }, /* … */ };This removes the need for an explicit
<head>
element and keeps all document metadata in one place.
33-36
: Inline<head>
becomes redundant oncemetadata.icons
is used
If you adopt the suggestion above, the specialised<head>
block (lines 34-36) can be deleted entirely.- <head> - <link rel="icon" href="/assets/nebula/favicon.ico" /> - </head>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
apps/nebula/src/app/opengraph-image.png
is excluded by!**/*.png
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (194)
apps/dashboard/.env.example
(0 hunks)apps/dashboard/package.json
(0 hunks)apps/dashboard/src/@/components/Responsive.tsx
(1 hunks)apps/dashboard/src/@/components/blocks/client-only.tsx
(1 hunks)apps/dashboard/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/dashboard/src/@/components/ui/Spinner/Spinner.module.css
(0 hunks)apps/dashboard/src/@/components/ui/button.tsx
(1 hunks)apps/dashboard/src/@/components/ui/skeleton.tsx
(1 hunks)apps/dashboard/src/@/constants/public-envs.ts
(0 hunks)apps/dashboard/src/@/constants/server-envs.ts
(0 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
(3 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/login/LoginPage.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx
(1 hunks)apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx
(1 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
(0 hunks)apps/dashboard/src/app/nebula-app/layout.tsx
(0 hunks)apps/dashboard/src/app/nebula-app/nebula-global.css
(0 hunks)apps/dashboard/src/app/nebula-app/readme.md
(0 hunks)apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
(0 hunks)apps/dashboard/src/components/CustomChat/ChatBar.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChatContent.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/CustomChats.tsx
(1 hunks)apps/dashboard/src/components/CustomChat/types.ts
(1 hunks)apps/dashboard/src/components/explore/contract-card/index.tsx
(1 hunks)apps/dashboard/src/middleware.ts
(0 hunks)apps/dashboard/src/stories/stubs.ts
(0 hunks)apps/nebula/.env.example
(1 hunks)apps/nebula/.eslintignore
(1 hunks)apps/nebula/.eslintrc.js
(1 hunks)apps/nebula/.storybook/main.ts
(1 hunks)apps/nebula/.storybook/preview.tsx
(1 hunks)apps/nebula/LICENSE.md
(1 hunks)apps/nebula/README.md
(1 hunks)apps/nebula/biome.json
(1 hunks)apps/nebula/components.json
(1 hunks)apps/nebula/knip.json
(1 hunks)apps/nebula/lucide-react.d.ts
(1 hunks)apps/nebula/next-sitemap.config.js
(1 hunks)apps/nebula/next.config.ts
(1 hunks)apps/nebula/package.json
(1 hunks)apps/nebula/postcss.config.js
(1 hunks)apps/nebula/src/@/components/blocks/ChainIcon.tsx
(1 hunks)apps/nebula/src/@/components/blocks/FormFieldSetup.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/Img.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx
(1 hunks)apps/nebula/src/@/components/blocks/MultiNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/NetworkSelectors.tsx
(1 hunks)apps/nebula/src/@/components/blocks/SingleNetworkSelector.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/auto-connect.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx
(1 hunks)apps/nebula/src/@/components/blocks/client-only.tsx
(2 hunks)apps/nebula/src/@/components/blocks/multi-select.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/multi-select.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.stories.tsx
(1 hunks)apps/nebula/src/@/components/blocks/select-with-search.tsx
(1 hunks)apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx
(1 hunks)apps/nebula/src/@/components/blocks/wallet-address.tsx
(1 hunks)apps/nebula/src/@/components/color-mode-toggle.tsx
(1 hunks)apps/nebula/src/@/components/ui/CopyTextButton.tsx
(1 hunks)apps/nebula/src/@/components/ui/DynamicHeight.tsx
(1 hunks)apps/nebula/src/@/components/ui/NavLink.tsx
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css
(1 hunks)apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.module.css
(1 hunks)apps/nebula/src/@/components/ui/Spinner/Spinner.tsx
(1 hunks)apps/nebula/src/@/components/ui/avatar.tsx
(1 hunks)apps/nebula/src/@/components/ui/badge.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/button.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/RenderCode.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.client.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/getCodeHtml.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/code/plaintext-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/decimal-input.tsx
(1 hunks)apps/nebula/src/@/components/ui/dialog.tsx
(1 hunks)apps/nebula/src/@/components/ui/form.tsx
(1 hunks)apps/nebula/src/@/components/ui/hover-card.tsx
(1 hunks)apps/nebula/src/@/components/ui/inline-code.tsx
(1 hunks)apps/nebula/src/@/components/ui/input.tsx
(1 hunks)apps/nebula/src/@/components/ui/label.tsx
(1 hunks)apps/nebula/src/@/components/ui/popover.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/select.tsx
(1 hunks)apps/nebula/src/@/components/ui/separator.tsx
(1 hunks)apps/nebula/src/@/components/ui/sheet.tsx
(1 hunks)apps/nebula/src/@/components/ui/skeleton.tsx
(1 hunks)apps/nebula/src/@/components/ui/sonner.tsx
(1 hunks)apps/nebula/src/@/components/ui/switch.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.stories.tsx
(1 hunks)apps/nebula/src/@/components/ui/table.tsx
(1 hunks)apps/nebula/src/@/components/ui/tabs.tsx
(1 hunks)apps/nebula/src/@/components/ui/text-shimmer.tsx
(1 hunks)apps/nebula/src/@/components/ui/textarea.tsx
(1 hunks)apps/nebula/src/@/components/ui/tooltip.tsx
(1 hunks)apps/nebula/src/@/config/sdk-component-theme.ts
(1 hunks)apps/nebula/src/@/constants/env-utils.ts
(1 hunks)apps/nebula/src/@/constants/local-node.ts
(1 hunks)apps/nebula/src/@/constants/nebula-client.ts
(1 hunks)apps/nebula/src/@/constants/public-envs.ts
(1 hunks)apps/nebula/src/@/constants/server-envs.ts
(1 hunks)apps/nebula/src/@/constants/urls.ts
(1 hunks)apps/nebula/src/@/data/eth-sanctioned-addresses.ts
(1 hunks)apps/nebula/src/@/hooks/chains.ts
(1 hunks)apps/nebula/src/@/hooks/use-clipboard.tsx
(1 hunks)apps/nebula/src/@/icons/NebulaIcon.tsx
(1 hunks)apps/nebula/src/@/lib/DashboardRouter.tsx
(1 hunks)apps/nebula/src/@/lib/reactive.ts
(1 hunks)apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts
(1 hunks)apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts
(1 hunks)apps/nebula/src/@/lib/useShowMore.ts
(1 hunks)apps/nebula/src/@/lib/utils.ts
(1 hunks)apps/nebula/src/@/storybook/stubs.ts
(1 hunks)apps/nebula/src/@/storybook/utils.tsx
(1 hunks)apps/nebula/src/@/types/chain.ts
(1 hunks)apps/nebula/src/@/utils/authToken.ts
(1 hunks)apps/nebula/src/@/utils/fetchChain.ts
(1 hunks)apps/nebula/src/@/utils/loginRedirect.ts
(1 hunks)apps/nebula/src/@/utils/map-chains.ts
(1 hunks)apps/nebula/src/@/utils/nebula-chains.ts
(1 hunks)apps/nebula/src/@/utils/parse-error.tsx
(1 hunks)apps/nebula/src/@/utils/vercel-utils.ts
(1 hunks)apps/nebula/src/@/utils/verifyTurnstileToken.ts
(1 hunks)apps/nebula/src/app/(app)/api/chat.ts
(1 hunks)apps/nebula/src/app/(app)/api/feedback.ts
(1 hunks)apps/nebula/src/app/(app)/api/session.ts
(1 hunks)apps/nebula/src/app/(app)/api/types.ts
(1 hunks)apps/nebula/src/app/(app)/chat/[session_id]/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/history/page.tsx
(1 hunks)apps/nebula/src/app/(app)/chat/page.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatBar.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageContent.tsx
(2 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatPageLayout.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ChatSidebar.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chatbar.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Chats.tsx
(1 hunks)apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx
(2 hunks)apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx
(4 hunks)apps/nebula/src/app/(app)/components/Swap/common.tsx
(6 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx
(1 hunks)apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx
(1 hunks)apps/nebula/src/app/(app)/data/examplePrompts.ts
(2 hunks)apps/nebula/src/app/(app)/layout.tsx
(1 hunks)apps/nebula/src/app/(app)/page.tsx
(1 hunks)apps/nebula/src/app/(app)/utils/getChainIds.ts
(1 hunks)apps/nebula/src/app/layout.tsx
(1 hunks)apps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx
(1 hunks)apps/nebula/src/app/login/NebulaLoginPage.tsx
(1 hunks)apps/nebula/src/app/login/auth-actions.ts
(1 hunks)apps/nebula/src/app/login/page.tsx
(1 hunks)apps/nebula/src/app/move-funds/connect-button.tsx
(1 hunks)apps/nebula/src/app/move-funds/dashboard-client.ts
(1 hunks)apps/nebula/src/app/move-funds/move-funds.tsx
(4 hunks)apps/nebula/src/app/move-funds/page.tsx
(1 hunks)apps/nebula/src/app/not-found.tsx
(2 hunks)apps/nebula/src/app/page.tsx
(0 hunks)apps/nebula/src/app/providers.tsx
(2 hunks)apps/nebula/src/global.css
(1 hunks)apps/nebula/tailwind.config.js
(1 hunks)apps/nebula/tsconfig.json
(2 hunks)apps/nebula/vercel.json
(1 hunks)apps/playground-web/src/components/ui/Spinner/Spinner.module.css
(0 hunks)apps/portal/src/components/ui/Spinner/Spinner.module.css
(0 hunks)
💤 Files with no reviewable changes (17)
- apps/dashboard/package.json
- apps/playground-web/src/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/@/constants/public-envs.ts
- apps/dashboard/src/@/constants/server-envs.ts
- apps/dashboard/src/components/ClientOnly/ClientOnly.module.css
- apps/nebula/src/app/page.tsx
- apps/dashboard/src/app/nebula-app/readme.md
- apps/dashboard/src/stories/stubs.ts
- apps/dashboard/src/app/nebula-app/nebula-global.css
- apps/portal/src/components/ui/Spinner/Spinner.module.css
- apps/dashboard/.env.example
- apps/dashboard/src/app/nebula-app/layout.tsx
- apps/dashboard/src/middleware.ts
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChatContent.tsx
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/actions.ts
- apps/dashboard/src/@/components/ui/Spinner/Spinner.module.css
- apps/dashboard/src/app/nebula-app/(app)/components/FloatingChat/FloatingChat.tsx
✅ Files skipped from review due to trivial changes (7)
- apps/nebula/src/app/(app)/components/Chatbar.stories.tsx
- apps/nebula/vercel.json
- apps/nebula/src/app/(app)/components/ChatPageLayout.tsx
- apps/nebula/src/@/components/ui/textarea.tsx
- apps/nebula/src/@/components/ui/decimal-input.tsx
- apps/nebula/src/@/constants/urls.ts
- apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.tsx
🚧 Files skipped from review as they are similar to previous changes (165)
- apps/dashboard/src/@/components/Responsive.tsx
- apps/dashboard/src/app/(app)/(dashboard)/tools/unixtime-converter/page.tsx
- apps/dashboard/src/@/components/color-mode-toggle.tsx
- apps/dashboard/src/components/explore/contract-card/index.tsx
- apps/dashboard/src/app/(app)/login/LoginPage.tsx
- apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.stories.tsx
- apps/nebula/src/app/(app)/components/ChatPageLayout.stories.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/token/token-info/token-info-fieldset.tsx
- apps/nebula/src/app/(app)/chat/history/ChatHistoryPage.stories.tsx
- apps/nebula/src/app/(app)/api/feedback.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/layout.tsx
- apps/nebula/src/app/login/NebulaLoginPage.tsx
- apps/nebula/README.md
- apps/dashboard/src/app/(app)/account/contracts/_components/DeployedContractsPage.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/(team)/layout.tsx
- apps/nebula/src/app/(app)/utils/getChainIds.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/connect/account-abstraction/factories/page.tsx
- apps/dashboard/src/@/components/ui/button.tsx
- apps/nebula/src/app/(app)/api/session.ts
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/components/server/products.ts
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/engine/dedicated/(instance)/[engineId]/explorer/components/engine-explorer.tsx
- apps/nebula/src/app/(app)/components/Reasoning/Reasoning.stories.tsx
- apps/nebula/src/app/(app)/components/Chats.stories.tsx
- apps/nebula/src/app/(app)/api/chat.ts
- apps/nebula/src/app/(app)/chat/history/page.tsx
- apps/nebula/src/app/(app)/components/Swap/SwapCards.stories.tsx
- apps/nebula/biome.json
- apps/nebula/lucide-react.d.ts
- apps/nebula/postcss.config.js
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectFTUX/ProjectFTUX.tsx
- apps/nebula/src/app/(app)/components/ChatBar.tsx
- apps/nebula/src/@/utils/authToken.ts
- apps/dashboard/src/app/(app)/(dashboard)/support/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/components/ProjectSidebarLayout.tsx
- apps/nebula/knip.json
- apps/nebula/src/app/move-funds/page.tsx
- apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.stories.tsx
- apps/nebula/src/app/(app)/components/EmptyStateChatPageContent.tsx
- apps/nebula/src/app/not-found.tsx
- apps/nebula/src/@/constants/env-utils.ts
- apps/nebula/src/@/components/blocks/auto-connect.tsx
- apps/nebula/src/app/(app)/chat/[session_id]/page.tsx
- apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/assets/create/nft/collection-info/nft-collection-info-fieldset.tsx
- apps/nebula/src/app/(app)/data/examplePrompts.ts
- apps/nebula/.eslintignore
- apps/nebula/src/@/lib/useIsomorphicLayoutEffect.ts
- apps/nebula/src/app/(app)/components/ExecuteTransactionCard.stories.tsx
- apps/nebula/src/app/move-funds/connect-button.tsx
- apps/dashboard/src/components/CustomChat/CustomChats.tsx
- apps/nebula/src/app/(app)/layout.tsx
- apps/nebula/components.json
- apps/nebula/src/app/(app)/api/types.ts
- apps/nebula/src/@/constants/nebula-client.ts
- apps/nebula/src/app/login/NebulaConnectEmbedLogin.tsx
- apps/nebula/src/app/(app)/components/Swap/SwapCards.tsx
- apps/nebula/src/app/(app)/components/ChatSidebar.tsx
- apps/nebula/src/@/components/ui/Spinner/Spinner.module.css
- apps/nebula/src/app/(app)/components/AssetsSection/AssetsSection.tsx
- apps/nebula/src/@/components/ui/inline-code.tsx
- apps/nebula/src/app/(app)/components/ExecuteTransactionCard.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/[contractAddress]/shared-layout.tsx
- apps/nebula/.storybook/main.ts
- apps/nebula/src/@/components/blocks/skeletons/GenericLoadingPage.tsx
- apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.module.css
- apps/nebula/src/@/components/ui/sonner.tsx
- apps/nebula/src/@/utils/loginRedirect.ts
- apps/nebula/src/@/components/ui/separator.tsx
- apps/nebula/src/app/providers.tsx
- apps/nebula/src/@/utils/nebula-chains.ts
- apps/nebula/src/@/components/ui/input.tsx
- apps/nebula/src/app/(app)/components/Chats.tsx
- apps/nebula/src/app/(app)/components/TransactionsSection/TransactionsSection.tsx
- apps/nebula/next-sitemap.config.js
- apps/nebula/src/@/storybook/stubs.ts
- apps/nebula/src/@/components/color-mode-toggle.tsx
- apps/nebula/src/app/login/auth-actions.ts
- apps/nebula/src/@/utils/fetchChain.ts
- apps/nebula/src/app/move-funds/move-funds.tsx
- apps/nebula/src/@/components/ui/text-shimmer.tsx
- apps/nebula/src/@/config/sdk-component-theme.ts
- apps/dashboard/src/@/components/ui/skeleton.tsx
- apps/dashboard/src/app/(app)/(dashboard)/(chain)/[chain_id]/(chainPage)/layout.tsx
- apps/nebula/src/@/constants/public-envs.ts
- apps/nebula/src/@/components/ui/popover.tsx
- apps/nebula/src/app/(app)/components/NebulaConnectButton.tsx
- apps/nebula/src/@/lib/resolveSchemeWithErrorHandler.ts
- apps/nebula/src/@/lib/utils.ts
- apps/nebula/src/app/move-funds/dashboard-client.ts
- apps/nebula/src/@/data/eth-sanctioned-addresses.ts
- apps/nebula/src/@/components/ui/label.tsx
- apps/nebula/src/@/components/ui/DynamicHeight.tsx
- apps/nebula/src/@/components/ui/Spinner/Spinner.tsx
- apps/nebula/src/app/login/page.tsx
- apps/nebula/src/@/components/ui/code/plaintext-code.stories.tsx
- apps/nebula/src/@/components/blocks/MultiNetworkSelector.stories.tsx
- apps/nebula/src/app/(app)/page.tsx
- apps/nebula/src/app/(app)/components/ChatPageContent.tsx
- apps/nebula/src/app/(app)/components/Swap/common.tsx
- apps/nebula/src/@/storybook/utils.tsx
- apps/nebula/src/@/utils/map-chains.ts
- apps/nebula/src/app/(app)/chat/page.tsx
- apps/nebula/src/@/components/blocks/ChainIcon.tsx
- apps/nebula/src/@/constants/server-envs.ts
- apps/nebula/next.config.ts
- apps/nebula/src/@/components/ui/switch.tsx
- apps/nebula/src/@/components/ui/code/code.client.tsx
- apps/nebula/src/@/hooks/use-clipboard.tsx
- apps/nebula/src/@/components/ui/button.stories.tsx
- apps/nebula/package.json
- apps/nebula/src/@/components/ui/avatar.tsx
- apps/nebula/tsconfig.json
- apps/nebula/src/@/components/ui/code/plaintext-code.tsx
- apps/nebula/src/@/hooks/chains.ts
- apps/nebula/src/@/components/blocks/Img.tsx
- apps/nebula/src/@/components/ui/sheet.tsx
- apps/nebula/src/@/components/blocks/select-with-search.stories.tsx
- apps/nebula/src/@/components/ui/NavLink.tsx
- apps/nebula/src/@/utils/verifyTurnstileToken.ts
- apps/nebula/src/@/components/blocks/Img.stories.tsx
- apps/nebula/src/@/components/ui/code/CodeBlockContainer.tsx
- apps/dashboard/src/@/components/blocks/client-only.tsx
- apps/dashboard/src/components/CustomChat/ChatBar.tsx
- apps/nebula/src/@/components/ui/code/RenderCode.tsx
- apps/nebula/src/@/components/blocks/FormFieldSetup.tsx
- apps/nebula/src/@/components/ui/select.stories.tsx
- apps/nebula/src/@/components/blocks/client-only.tsx
- apps/nebula/src/@/components/ui/button.tsx
- apps/nebula/src/global.css
- apps/nebula/.eslintrc.js
- apps/nebula/tailwind.config.js
- apps/nebula/src/@/icons/NebulaIcon.tsx
- apps/nebula/src/@/lib/useShowMore.ts
- apps/nebula/src/@/components/ui/CopyTextButton.tsx
- apps/dashboard/src/components/CustomChat/CustomChatContent.tsx
- apps/nebula/src/@/components/blocks/select-with-search.tsx
- apps/nebula/src/@/components/ui/code/getCodeHtml.tsx
- apps/nebula/src/app/(app)/components/Reasoning/Reasoning.tsx
- apps/nebula/src/@/components/blocks/multi-select.stories.tsx
- apps/nebula/src/@/utils/vercel-utils.ts
- apps/nebula/src/@/types/chain.ts
- apps/nebula/src/@/components/ui/badge.tsx
- apps/dashboard/src/components/CustomChat/types.ts
- apps/nebula/src/@/components/ui/table.tsx
- apps/nebula/src/@/components/ui/ScrollShadow/ScrollShadow.tsx
- apps/nebula/src/@/components/ui/code/code.stories.tsx
- apps/nebula/src/@/components/ui/dialog.tsx
- apps/nebula/src/@/components/blocks/MarkdownRenderer/markdown-renderer.stories.tsx
- apps/nebula/src/@/lib/DashboardRouter.tsx
- apps/nebula/.storybook/preview.tsx
- apps/nebula/src/@/components/ui/table.stories.tsx
- apps/nebula/src/@/components/ui/hover-card.tsx
- apps/nebula/src/@/components/blocks/wallet-address.tsx
- apps/nebula/src/@/utils/parse-error.tsx
- apps/nebula/src/@/components/ui/tooltip.tsx
- apps/nebula/src/@/components/blocks/buttons/TransactionButton.stories.tsx
- apps/nebula/src/@/components/blocks/multi-select.tsx
- apps/nebula/src/@/components/ui/select.tsx
- apps/nebula/src/@/components/blocks/buttons/TransactionButton.tsx
- apps/nebula/src/@/lib/reactive.ts
- apps/nebula/src/@/components/blocks/buttons/MismatchButton.tsx
- apps/nebula/src/@/components/ui/skeleton.tsx
- apps/nebula/src/@/components/ui/form.tsx
- apps/nebula/src/@/components/blocks/SingleNetworkSelector.stories.tsx
- apps/nebula/src/@/components/blocks/NetworkSelectors.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/nebula/src/app/layout.tsx (2)
apps/login/src/lib/utils.ts (1)
cn
(4-6)apps/dashboard/src/@/lib/DashboardRouter.tsx (1)
DashboardRouterTopProgressBar
(49-119)
🪛 dotenv-linter (3.3.0)
apps/nebula/.env.example
[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")
[warning] 2-2: [QuoteCharacter] The value has quote characters (', ")
🪛 LanguageTool
apps/nebula/LICENSE.md
[uncategorized] ~150-~150: Possible missing comma found.
Context: ...iateness of using or redistributing the Work and assume any risks associated wit...
(AI_HYDRA_LEO_MISSING_COMMA)
[style] ~161-~161: ‘any and all’ might be wordy. Consider a shorter alternative.
Context: ...ge, computer failure or malfunction, or any and all other commercial damages or losses)...
(EN_WORDINESS_PREMIUM_ANY_AND_ALL)
🪛 Gitleaks (8.26.0)
apps/nebula/src/@/constants/local-node.ts
5-6: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
⏰ Context from checks skipped due to timeout of 90000ms (6)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, vite)
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (2)
apps/nebula/src/app/layout.tsx (1)
3-4
: Verify path-alias points to the new Nebula copy ofDashboardRouter
The import uses the@/lib
alias that previously resolved into the dashboard package. Make suretsconfig.json
/eslint
paths insideapps/nebula
were updated to map@/*
toapps/nebula/src/*
; otherwise this will silently pick the dashboard copy (or fail at runtime).apps/nebula/LICENSE.md (1)
1-202
: Standard Apache 2.0 license – no issues
The text matches the official ASF template; nothing to flag.
PR-Codex overview
This PR focuses on refactoring and organizing the codebase, enhancing functionality, and improving the UI components in the
nebula
anddashboard
applications. It includes updates to imports, adding new features, and cleaning up unused files.Detailed summary
Spinner
,ChatBar
, andSkeleton
.Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Chores
Documentation