Skip to content

Commit

Permalink
[Dashboard] Nebula - Update context filters + Add OG image (#5736)
Browse files Browse the repository at this point in the history
## Problem solved

DASH-615

<!-- start pr-codex -->

---

## PR-Codex overview
This PR primarily focuses on enhancing the context filter functionality within the application by introducing support for `walletAddresses`, updating related types, and modifying components to accommodate these changes.

### Detailed summary
- Added `walletAddresses` to various types and API parameters.
- Updated `SessionContextFilter` to include `wallet_addresses`.
- Modified `ChatPageContent` to handle and display `walletAddresses`.
- Enhanced `ContextFiltersButton` to show wallet address badges.
- Updated form handling to include validation for `walletAddresses`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
  • Loading branch information
MananTank committed Dec 13, 2024
1 parent 22bc557 commit 9b58a08
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 48 deletions.
1 change: 1 addition & 0 deletions apps/dashboard/src/app/nebula-app/(app)/api/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { ExecuteConfig } from "./types";
export type ContextFilters = {
chainIds?: string[];
contractAddresses?: string[];
walletAddresses?: string[];
};

export async function promptNebula(params: {
Expand Down
2 changes: 2 additions & 0 deletions apps/dashboard/src/app/nebula-app/(app)/api/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export async function createSession(params: {
body.context_filter = {
chain_ids: params.contextFilters.chainIds || [],
contract_addresses: params.contextFilters.contractAddresses || [],
wallet_addresses: params.contextFilters.walletAddresses || [],
};
}

Expand Down Expand Up @@ -62,6 +63,7 @@ export async function updateSession(params: {
body.context_filter = {
chain_ids: params.contextFilters.chainIds || [],
contract_addresses: params.contextFilters.contractAddresses || [],
wallet_addresses: params.contextFilters.walletAddresses || [],
};
}

Expand Down
16 changes: 8 additions & 8 deletions apps/dashboard/src/app/nebula-app/(app)/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ type ClientConfig = {

export type ExecuteConfig = EngineConfig | SessionKeyConfig | ClientConfig;

type SessionContextFilter = {
chain_ids: string[] | null;
contract_addresses: string[] | null;
wallet_addresses: string[] | null;
};

export type SessionInfo = {
id: string;
account_id: string;
Expand All @@ -37,10 +43,7 @@ export type SessionInfo = {
archived_at: string | null;
title: string | null;
is_public: boolean | null;
context_filter: {
chain_ids: string[];
contract_addresses: string[];
} | null;
context_filter: SessionContextFilter | null;
// memory
// action: array<object> | null; <-- type of this is not available on https://nebula-api.thirdweb-dev.com/docs#/default/get_session_session__session_id__get
};
Expand All @@ -50,10 +53,7 @@ export type UpdatedSessionInfo = {
modal_name: string;
account_id: string;
execute_config: ExecuteConfig | null;
context_filter: {
chain_ids: string[];
contract_addresses: string[];
} | null;
context_filter: SessionContextFilter | null;
};

export type DeletedSessionInfo = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { ScrollShadow } from "@/components/ui/ScrollShadow/ScrollShadow";
import { useThirdwebClient } from "@/constants/thirdweb.client";
import type { Account } from "@3rdweb-sdk/react/hooks/useApi";
import { useMutation } from "@tanstack/react-query";
import { useEffect, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { useActiveAccount } from "thirdweb/react";
import { type ContextFilters, promptNebula } from "../api/chat";
import { createSession, updateSession } from "../api/session";
import type { ExecuteConfig, SessionInfo } from "../api/types";
Expand All @@ -22,6 +23,7 @@ export function ChatPageContent(props: {
type: "landing" | "new-chat";
account: Account;
}) {
const address = useActiveAccount()?.address;
const client = useThirdwebClient();
const [userHasSubmittedMessage, setUserHasSubmittedMessage] = useState(false);
const [messages, setMessages] = useState<Array<ChatMessage>>(() => {
Expand All @@ -36,17 +38,47 @@ export function ChatPageContent(props: {
});

const [_config, setConfig] = useState<ExecuteConfig | null>();
const [contextFilters, setContextFilters] = useState<
const [hasUserUpdatedContextFilters, setHasUserUpdatedContextFilters] =
useState(false);

const [_contextFilters, _setContextFilters] = useState<
ContextFilters | undefined
>(() => {
const contextFilterRes = props.session?.context_filter;
if (contextFilterRes) {
const value: ContextFilters = {
chainIds: contextFilterRes?.chain_ids || undefined,
contractAddresses: contextFilterRes?.contract_addresses || undefined,
walletAddresses: contextFilterRes?.wallet_addresses || undefined,
};

return value;
});

function setContextFilters(filters: ContextFilters | undefined) {
_setContextFilters(filters);
setHasUserUpdatedContextFilters(true);
}

const isNewSession = !props.session;

// if this is a new session, user has not manually updated context filters
// and no wallet address is set in context filters, add the current wallet address
const contextFilters = useMemo(() => {
if (
isNewSession &&
!hasUserUpdatedContextFilters &&
address &&
(!_contextFilters?.walletAddresses ||
_contextFilters.walletAddresses.length === 0)
) {
return {
chainIds: contextFilterRes.chain_ids,
contractAddresses: contextFilterRes.contract_addresses,
..._contextFilters,
walletAddresses: [address],
};
}
});

return _contextFilters;
}, [_contextFilters, address, isNewSession, hasUserUpdatedContextFilters]);

const config = _config || {
mode: "client",
Expand Down Expand Up @@ -293,7 +325,7 @@ export function ChatPageContent(props: {

return (
<div className="flex grow flex-col overflow-hidden">
<header className="flex justify-end border-b bg-background p-4">
<header className="flex justify-start border-b bg-background p-4">
<ContextFiltersButton
contextFilters={contextFilters}
setContextFilters={setContextFilters}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,70 @@ export const Mobile: Story = {

function Story() {
return (
<div className="container flex max-w-[1000px] flex-col gap-8 lg:p-10">
<div className="container flex max-w-[1000px] flex-col gap-8 py-10 lg:p-10">
<Variant contextFilters={undefined} label="No Filters Set" />

<Variant
contextFilters={{
chainIds: ["1", "2", "3"],
chainIds: ["137"],
}}
label="Chain ids Set"
label="1 chain"
/>

<Variant
contextFilters={{
chainIds: ["137", "10", "421614"],
}}
label="Few chains"
/>

<Variant
contextFilters={{
contractAddresses: ["0x1E51e33F9838A5a043E099C60409f62aA564272f"],
}}
label="Contract addresses set"
label="1 contract"
/>

<Variant
contextFilters={{
contractAddresses: [
"0x1E51e33F9838A5a043E099C60409f62aA564272f",
"0xF61c8d5492139b40af09bDB353733d5F0a348aCf",
],
}}
label="Few contracts"
/>

<Variant
contextFilters={{
walletAddresses: ["0x1F846F6DAE38E1C88D71EAA191760B15f38B7A37"],
}}
label="1 wallet"
/>

<Variant
contextFilters={{
walletAddresses: [
"0x1F846F6DAE38E1C88D71EAA191760B15f38B7A37",
"0x83Dd93fA5D8343094f850f90B3fb90088C1bB425",
],
}}
label="Few wallets"
/>

<Variant
contextFilters={{
chainIds: ["137", "10", "421614"],
contractAddresses: [
"0x1E51e33F9838A5a043E099C60409f62aA564272f",
"0xF61c8d5492139b40af09bDB353733d5F0a348aCf",
],
walletAddresses: [
"0x1F846F6DAE38E1C88D71EAA191760B15f38B7A37",
"0x83Dd93fA5D8343094f850f90B3fb90088C1bB425",
],
}}
label="chains + wallets + contracts"
/>
<Toaster richColors />
</div>
Expand Down
120 changes: 91 additions & 29 deletions apps/dashboard/src/app/nebula-app/(app)/components/ContextFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { Spinner } from "@/components/ui/Spinner/Spinner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Dialog,
Expand Down Expand Up @@ -42,14 +43,46 @@ export default function ContextFiltersButton(props: {
mutationFn: props.updateContextFilters,
});

const chainIds = props.contextFilters?.chainIds;
const contractAddresses = props.contextFilters?.contractAddresses;
const walletAddresses = props.contextFilters?.walletAddresses;

return (
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogTrigger asChild>
<Button size="sm" variant="outline" className="gap-2">
<SlidersHorizontalIcon className="size-4" />
{props.contextFilters
? "Edit Context Filters"
: "Set context filters"}
<Button size="sm" variant="outline" className="max-w-full gap-2">
<SlidersHorizontalIcon className="size-3.5 shrink-0 text-muted-foreground" />
Context Filters
<div className="flex gap-1 overflow-hidden">
{chainIds && chainIds.length > 0 && (
<Badge className="gap-1 truncate">
Chain
<span className="max-sm:hidden">{chainIds.join(", ")}</span>
</Badge>
)}

{contractAddresses && contractAddresses.length > 0 && (
<Badge className="gap-1 truncate">
Contract
<span className="max-sm:hidden">
{contractAddresses
.map((add) => `${add.trim().slice(0, 6)}..`)
.join(", ")}
</span>
</Badge>
)}

{walletAddresses && walletAddresses.length > 0 && (
<Badge className="gap-1 truncate">
Wallet
<span className="max-sm:hidden">
{walletAddresses
.map((add) => `${add.trim().slice(0, 6)}..`)
.join(", ")}
</span>
</Badge>
)}
</div>
</Button>
</DialogTrigger>
<DialogContent className="p-0">
Expand All @@ -74,6 +107,18 @@ export default function ContextFiltersButton(props: {
);
}

const commaSeparateListOfAddresses = z.string().refine(
(s) => {
if (s.trim() === "") {
return true;
}
return s.split(",").every((s) => isAddress(s.trim()));
},
{
message: "Must be a comma-separated list of valid addresses",
},
);

const formSchema = z.object({
chainIds: z.string().refine(
(s) => {
Expand All @@ -89,18 +134,8 @@ const formSchema = z.object({
message: "Chain IDs must be a comma-separated list of integers",
},
),
contractAddresses: z.string().refine(
(s) => {
if (s.trim() === "") {
return true;
}
return s.trim().split(",").every(isAddress);
},
{
message:
"Contract addresses must be a comma-separated list of valid addresses",
},
),
contractAddresses: commaSeparateListOfAddresses,
walletAddresses: commaSeparateListOfAddresses,
});

function ContextFilterDialogContent(props: {
Expand All @@ -117,25 +152,31 @@ function ContextFilterDialogContent(props: {
contractAddresses: props.contextFilters?.contractAddresses
? props.contextFilters.contractAddresses.join(",")
: "",
walletAddresses: props.contextFilters?.walletAddresses
? props.contextFilters.walletAddresses.join(",")
: "",
},
reValidateMode: "onChange",
});

function onSubmit(values: z.infer<typeof formSchema>) {
const { chainIds, contractAddresses } = values;
const chainIdsArray = chainIds.trim().split(",").filter(Boolean);
const { chainIds, contractAddresses, walletAddresses } = values;

const chainIdsArray = chainIds.split(",").filter((id) => id.trim());

const contractAddressesArray = contractAddresses
.trim()
.split(",")
.filter(Boolean);
if (chainIdsArray.length === 0 && contractAddressesArray.length === 0) {
props.updateFilters(undefined);
} else {
props.updateFilters({
chainIds: chainIdsArray,
contractAddresses: contractAddressesArray,
});
}
.filter((v) => v.trim());

const walletAddressesArray = walletAddresses
.split(",")
.filter((v) => v.trim());

props.updateFilters({
chainIds: chainIdsArray,
contractAddresses: contractAddressesArray,
walletAddresses: walletAddressesArray,
});
}

return (
Expand Down Expand Up @@ -195,6 +236,27 @@ function ContextFilterDialogContent(props: {
</FormItem>
)}
/>

<FormField
control={form.control}
name="walletAddresses"
render={({ field }) => (
<FormItem>
<FormLabel>Wallet Addresses</FormLabel>
<FormControl>
<AutoResizeTextarea
{...field}
placeholder="0x123..., 0x456..."
className="min-h-[32px] resize-none"
/>
</FormControl>
<FormDescription>
Comma separated list of wallet addresses
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div>

<div className="mt-10 flex justify-end gap-3 border-t bg-muted/50 p-6">
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 9b58a08

Please sign in to comment.