Compare commits

...

61 Commits

Author SHA1 Message Date
Abhimanyu Yadav
54bbafc431 Merge branch 'dev' into ci-chromatic 2025-04-22 20:26:42 +05:30
Abhimanyu Yadav
5662783624 Merge branch 'dev' into ci-chromatic 2025-04-22 10:29:24 +05:30
Nicholas Tindle
a5f448af98 Merge branch 'dev' into ci-chromatic 2025-03-06 11:24:49 -06:00
Nicholas Tindle
c766bd66e1 fix(frontend): typechecking 2025-02-05 17:15:24 -06:00
Nicholas Tindle
6d11ad8051 fix(frontend): format 2025-02-05 17:12:33 -06:00
Nicholas Tindle
d476983bd2 fix: doesn't crash 2025-02-05 17:10:21 -06:00
Nicholas Tindle
3ac1ce5a3f fix: format 2025-02-05 16:50:51 -06:00
Nicholas Tindle
3b89e6d2b7 Merge branch 'ci-chromatic' of https://github.com/Significant-Gravitas/AutoGPT into ci-chromatic 2025-02-05 16:49:32 -06:00
Nicholas Tindle
c7a7652b9f Merge branch 'dev' into ci-chromatic 2025-02-05 16:47:46 -06:00
Nicholas Tindle
b6b0d0b209 Merge branch 'dev' into ci-chromatic 2025-02-03 11:55:31 -06:00
Nicholas Tindle
a5b1495062 Merge branch 'dev' into ci-chromatic 2025-02-03 07:13:53 -06:00
Nicholas Tindle
026f16c10f Merge branch 'dev' into ci-chromatic 2025-01-31 04:50:48 -06:00
Nicholas Tindle
c468201c53 Update mock_client.ts 2025-01-29 07:10:03 -06:00
Nicholas Tindle
5beb581d1c feat(frontend): minimocking 2025-01-29 07:04:38 -06:00
Nicholas Tindle
df2339c1cf feat: add mock backend for rendering the storybook stuff 2025-01-29 06:46:50 -06:00
Nicholas Tindle
327db54321 Merge branch 'open-2047-add-type-checking-step-to-front-end-ci' into ci-chromatic 2025-01-29 12:26:19 +00:00
Nicholas Tindle
234d6f78ba Merge branch 'dev' into open-2047-add-type-checking-step-to-front-end-ci 2025-01-29 12:17:23 +00:00
Nicholas Tindle
43088ddff8 fix: incorrect meshing of types and test 2025-01-29 06:16:28 -06:00
Nicholas Tindle
fd955fba25 ref: add providers to the story previews 2025-01-29 05:35:56 -06:00
Nicholas Tindle
83943d9ddb Merge branch 'open-2047-add-type-checking-step-to-front-end-ci' into ci-chromatic 2025-01-29 10:57:00 +00:00
Nicholas Tindle
60c26e62f6 Merge branch 'dev' into open-2047-add-type-checking-step-to-front-end-ci 2025-01-29 10:53:51 +00:00
Nicholas Tindle
1fc8f9ba66 fix: handle conditions better for feature flagging 2025-01-28 18:04:41 +00:00
Nicholas Tindle
33d747f457 ref: remove unused code 2025-01-28 16:39:11 +00:00
Nicholas Tindle
06fa001a37 ref: use data structure for copy and paste data 2025-01-28 16:36:07 +00:00
Nicholas Tindle
4e7b56b814 ref: pr changes 2025-01-28 16:31:25 +00:00
Nicholas Tindle
d6b03a4f18 ref: pr change request 2025-01-28 16:30:13 +00:00
Nicholas Tindle
fae9aeb49a fix: linting 2025-01-28 16:30:05 +00:00
Nicholas Tindle
5e8c1e274e fix: linting 2025-01-28 16:29:58 +00:00
Nicholas Tindle
55f7dc4853 fix: drop classname unused 2025-01-28 16:25:23 +00:00
Nicholas Tindle
b317adb9cf ref: remove classname from navbar link 2025-01-28 16:23:14 +00:00
Nicholas Tindle
c873ba04b8 ref: split out type-check step + fix tsc error 2025-01-28 15:38:05 +00:00
Nicholas Tindle
00f0311dd0 ref: split out type-check step + fix tsc error 2025-01-28 15:31:52 +00:00
Nicholas Tindle
9b2bd756fa Update platform-frontend-ci.yml 2025-01-28 15:17:42 +00:00
Nicholas Tindle
bceb83ca30 fix: workingdir required 2025-01-28 15:17:42 +00:00
Nicholas Tindle
eadbfcd920 Update platform-frontend-ci.yml 2025-01-28 15:17:41 +00:00
SwiftyOS
9768540b60 Merge branch 'dev' into open-2047-add-type-checking-step-to-front-end-ci 2025-01-28 15:46:21 +01:00
Nicholas Tindle
697436be07 Merge branch 'dev' into open-2047-add-type-checking-step-to-front-end-ci 2025-01-28 07:53:27 +00:00
Nicholas Tindle
d725e105a0 Merge branch 'dev' into open-2047-add-type-checking-step-to-front-end-ci 2025-01-26 15:27:50 +01:00
Nicholas Tindle
927f43f52f fix: formatting 2025-01-26 12:18:11 +00:00
Nicholas Tindle
eedcc92d6f fix: add secret to all the subschemas 2025-01-26 12:15:37 +00:00
Nicholas Tindle
f0c378c70d fix: missing type addition 2025-01-26 12:12:12 +00:00
Nicholas Tindle
c6c2b852df fix: missing inputs based on changes 2025-01-26 12:11:37 +00:00
Nicholas Tindle
aaab8b1e0e fix: more formatting 2025-01-26 11:56:07 +00:00
Nicholas Tindle
a4eeb4535a fix: formatting 2025-01-26 11:55:56 +00:00
Nicholas Tindle
db068c598c fix: missing types 2025-01-26 11:46:35 +00:00
Nicholas Tindle
d4d9efc73e fix: missing attribute 2025-01-26 11:46:25 +00:00
Nicholas Tindle
ffaf77df4e fix: type the params 2025-01-26 11:46:10 +00:00
Nicholas Tindle
2daf08434e fix: type the params 2025-01-26 11:46:01 +00:00
Nicholas Tindle
745137f4c2 fix: pass correct subclass 2025-01-26 11:45:46 +00:00
Nicholas Tindle
3a2c3deb0e fix: remove import + impossible case 2025-01-26 11:45:34 +00:00
Nicholas Tindle
66a15a7b8c fix: user correct object when deleting 2025-01-26 11:44:25 +00:00
Nicholas Tindle
669c61de76 fix: take in classnames as used by the outer component
we probbaly shouldn't be doing this?
2025-01-26 11:44:04 +00:00
Nicholas Tindle
e860bde3d4 fix: coalesce types and use a default
@aarushik93 is this okay?
2025-01-26 11:43:40 +00:00
Nicholas Tindle
f5394f6d65 fix: expose interface for sub object so it can be used in other places to fix type errors 2025-01-26 11:43:00 +00:00
Nicholas Tindle
06e845abe7 feat: take in props for navbar
Is this desired?
2025-01-26 11:42:28 +00:00
Nicholas Tindle
c2c3c29018 fix: use proper state object 2025-01-26 11:42:08 +00:00
Nicholas Tindle
31fd0b557a fix: add missing import 2025-01-26 11:41:44 +00:00
Nicholas Tindle
9350fe1d2b fix: fully disable unused page 2025-01-26 11:41:12 +00:00
Nicholas Tindle
5ae92820b4 fix: remove unused classnames 2025-01-26 11:40:57 +00:00
Nicholas Tindle
66a87e5a14 ci: typechecker for frontend 2025-01-26 11:22:38 +00:00
Nicholas Tindle
e1f8882e2d fix: stories being broken 2025-01-26 11:18:12 +00:00
9 changed files with 267 additions and 88 deletions

View File

@@ -56,6 +56,30 @@ jobs:
run: |
yarn type-check
design:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "21"
- name: Install dependencies
run: |
yarn install --frozen-lockfile
- name: Run Chromatic
uses: chromaui/action@latest
with:
# ⚠️ Make sure to configure a `CHROMATIC_PROJECT_TOKEN` repository secret
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
workingDir: autogpt_platform/frontend
test:
runs-on: ubuntu-latest
strategy:

View File

@@ -1,8 +1,9 @@
import type { Preview } from "@storybook/react";
import { initialize, mswLoader } from "msw-storybook-addon";
import "../src/app/globals.css";
import { Providers } from "../src/app/providers";
// Initialize MSW
import React from "react";
initialize();
const preview: Preview = {
@@ -18,6 +19,17 @@ const preview: Preview = {
},
},
loaders: [mswLoader],
decorators: [
(Story, context) => {
const mockOptions = context.parameters.mockBackend || {};
return (
<Providers useMockBackend mockClientProps={mockOptions}>
<Story />
</Providers>
);
},
],
};
export default preview;

View File

@@ -7,12 +7,27 @@ import { BackendAPIProvider } from "@/lib/autogpt-server-api/context";
import { TooltipProvider } from "@/components/ui/tooltip";
import CredentialsProvider from "@/components/integrations/credentials-provider";
import { LaunchDarklyProvider } from "@/components/feature-flag/feature-flag-provider";
import { MockClientProps } from "@/lib/autogpt-server-api/mock_client";
import OnboardingProvider from "@/components/onboarding/onboarding-provider";
export function Providers({ children, ...props }: ThemeProviderProps) {
export interface ProvidersProps extends ThemeProviderProps {
children: React.ReactNode;
useMockBackend?: boolean;
mockClientProps?: MockClientProps;
}
export function Providers({
children,
useMockBackend,
mockClientProps,
...props
}: ProvidersProps) {
return (
<NextThemesProvider {...props}>
<BackendAPIProvider>
<BackendAPIProvider
useMockBackend={useMockBackend}
mockClientProps={mockClientProps}
>
<CredentialsProvider>
<LaunchDarklyProvider>
<OnboardingProvider>

View File

@@ -15,8 +15,8 @@ export interface AgentTableCardProps {
imageSrc: string[];
dateSubmitted: string;
status: StatusType;
runs: number;
rating: number;
runs?: number;
rating?: number;
id: number;
onEditSubmission: (submission: StoreSubmissionRequest) => void;
}
@@ -82,11 +82,11 @@ export const AgentTableCard: React.FC<AgentTableCardProps> = ({
{dateSubmitted}
</div>
<div className="text-sm text-neutral-600 dark:text-neutral-400">
{runs.toLocaleString()} runs
{runs ? runs.toLocaleString() : "N/A"} runs
</div>
<div className="flex items-center gap-1">
<span className="text-sm font-medium text-neutral-800 dark:text-neutral-200">
{rating.toFixed(1)}
{rating ? rating.toFixed(1) : "N/A"}
</span>
<IconStarFilled className="h-4 w-4 text-neutral-800 dark:text-neutral-200" />
</div>

View File

@@ -3,8 +3,6 @@ import { Navbar } from "./Navbar";
import { userEvent, within } from "@storybook/test";
import { IconType } from "../ui/icons";
import { ProfileDetails } from "@/lib/autogpt-server-api/types";
// You can't import this here, jest is not available in storybook and will crash it
// import { jest } from "@jest/globals";
// Mock the API responses
const mockProfileData: ProfileDetails = {
@@ -15,40 +13,6 @@ const mockProfileData: ProfileDetails = {
avatar_url: "https://avatars.githubusercontent.com/u/123456789?v=4",
};
const mockCreditData = {
credits: 1500,
};
// Mock the API module
// jest.mock("@/lib/autogpt-server-api", () => {
// return function () {
// return {
// getStoreProfile: () => Promise.resolve(mockProfileData),
// getUserCredit: () => Promise.resolve(mockCreditData),
// };
// };
// });
const meta = {
title: "AGPT UI/Navbar",
component: Navbar,
parameters: {
layout: "fullscreen",
},
tags: ["autodocs"],
argTypes: {
// isLoggedIn: { control: "boolean" },
// avatarSrc: { control: "text" },
links: { control: "object" },
// activeLink: { control: "text" },
menuItemGroups: { control: "object" },
// params: { control: { type: "object", defaultValue: { lang: "en" } } },
},
} satisfies Meta<typeof Navbar>;
export default meta;
type Story = StoryObj<typeof meta>;
const defaultMenuItemGroups = [
{
items: [
@@ -89,35 +53,83 @@ const defaultLinks = [
{ name: "Build", href: "/builder" },
];
const meta = {
title: "AGPT UI/Navbar",
component: Navbar,
parameters: {
layout: "fullscreen",
},
tags: ["autodocs"],
argTypes: {
links: { control: "object" },
menuItemGroups: { control: "object" },
mockUser: { control: "object" },
mockClientProps: { control: "object" },
},
} satisfies Meta<typeof Navbar>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
// params: { lang: "en" },
// isLoggedIn: true,
links: defaultLinks,
// activeLink: "/marketplace",
// avatarSrc: mockProfileData.avatar_url,
menuItemGroups: defaultMenuItemGroups,
mockUser: {
id: "123",
email: "test@test.com",
user_metadata: {
name: "Test User",
},
app_metadata: {
provider: "email",
},
aud: "test",
created_at: new Date().toISOString(),
},
mockClientProps: {
credits: 1500,
profile: mockProfileData,
},
},
parameters: {
mockBackend: {
credits: 1500,
profile: mockProfileData,
},
},
};
export const WithActiveLink: Story = {
export const WithCredits: Story = {
args: {
...Default.args,
// activeLink: "/library",
},
parameters: {
mockBackend: {
credits: 1500,
},
},
};
export const LongUserName: Story = {
export const WithLargeCredits: Story = {
args: {
...Default.args,
// avatarSrc: "https://avatars.githubusercontent.com/u/987654321?v=4",
},
parameters: {
mockBackend: {
credits: 999999,
},
},
};
export const NoAvatar: Story = {
export const WithZeroCredits: Story = {
args: {
...Default.args,
// avatarSrc: undefined,
},
parameters: {
mockBackend: {
credits: 0,
},
},
};
@@ -125,6 +137,12 @@ export const WithInteraction: Story = {
args: {
...Default.args,
},
parameters: {
mockBackend: {
credits: 1500,
profile: mockProfileData,
},
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const profileTrigger = canvas.getByRole("button");
@@ -135,29 +153,3 @@ export const WithInteraction: Story = {
await canvas.findByText("Edit profile");
},
};
export const NotLoggedIn: Story = {
args: {
...Default.args,
// isLoggedIn: false,
// avatarSrc: undefined,
},
};
export const WithCredits: Story = {
args: {
...Default.args,
},
};
export const WithLargeCredits: Story = {
args: {
...Default.args,
},
};
export const WithZeroCredits: Story = {
args: {
...Default.args,
},
};

View File

@@ -9,6 +9,10 @@ import { ProfileDetails } from "@/lib/autogpt-server-api/types";
import { NavbarLink } from "./NavbarLink";
import getServerUser from "@/lib/supabase/getServerUser";
import BackendAPI from "@/lib/autogpt-server-api";
import { User } from "@supabase/supabase-js";
import MockClient, {
MockClientProps,
} from "@/lib/autogpt-server-api/mock_client";
// Disable theme toggle for now
// import { ThemeToggle } from "./ThemeToggle";
@@ -29,21 +33,33 @@ interface NavbarProps {
onClick?: () => void;
}[];
}[];
mockUser?: User;
mockClientProps?: MockClientProps;
}
async function getProfileData() {
async function getProfileData(mockClientProps?: MockClientProps) {
if (mockClientProps) {
const api = new MockClient(mockClientProps);
const profile = await Promise.resolve(api.getStoreProfile("navbar"));
return profile;
}
const api = new BackendAPI();
const profile = await Promise.resolve(api.getStoreProfile());
return profile;
}
export const Navbar = async ({ links, menuItemGroups }: NavbarProps) => {
const { user } = await getServerUser();
export const Navbar = async ({
links,
menuItemGroups,
mockUser,
mockClientProps,
}: NavbarProps) => {
const { user } = await getServerUser(mockUser);
const isLoggedIn = user !== null;
let profile: ProfileDetails | null = null;
if (isLoggedIn) {
profile = await getProfileData();
profile = await getProfileData(mockClientProps);
}
return (

View File

@@ -2,15 +2,27 @@
import BackendAPI from "./client";
import React, { createContext, useMemo } from "react";
import MockClient, { MockClientProps } from "./mock_client";
const BackendAPIProviderContext = createContext<BackendAPI | null>(null);
interface BackendAPIProviderProps {
children?: React.ReactNode;
useMockBackend?: boolean;
mockClientProps?: MockClientProps;
}
export function BackendAPIProvider({
children,
}: {
children?: React.ReactNode;
}): React.ReactNode {
const api = useMemo(() => new BackendAPI(), []);
useMockBackend,
mockClientProps,
}: BackendAPIProviderProps): React.ReactNode {
const api = useMemo(() => {
if (useMockBackend) {
return new MockClient(mockClientProps);
}
return new BackendAPI();
}, [useMockBackend, mockClientProps]);
return (
<BackendAPIProviderContext.Provider value={api}>

View File

@@ -0,0 +1,104 @@
import { faker } from "@faker-js/faker";
import BackendAPI from "./client";
import { Block, BlockUIType, ProfileDetails, User } from "./types";
export interface MockClientProps {
credits?: number;
blocks?: Block[];
profile?: ProfileDetails;
isAuthenticated?: boolean;
}
// Default mock data
export const DEFAULT_MOCK_DATA: Required<MockClientProps> = {
credits: 10,
blocks: [
{
id: faker.string.uuid(),
name: faker.lorem.word(),
description: faker.lorem.sentence(),
inputSchema: {
type: "object",
properties: {},
},
outputSchema: {
type: "object",
properties: {},
},
staticOutput: false,
categories: [],
uiType: BlockUIType.STANDARD,
costs: [],
hardcodedValues: {},
},
],
profile: {
name: "John Doe",
username: "johndoe",
description: "",
links: [],
avatar_url: "https://avatars.githubusercontent.com/u/123456789?v=4",
},
isAuthenticated: true,
};
export default class MockClient extends BackendAPI {
private props: Required<MockClientProps>;
constructor(props: MockClientProps = {}) {
super();
this.props = {
...DEFAULT_MOCK_DATA,
...props,
};
}
override isAuthenticated(): Promise<boolean> {
return Promise.resolve(this.props.isAuthenticated);
}
override createUser(): Promise<User> {
return Promise.resolve({
id: faker.string.uuid(),
email: "test@test.com",
} satisfies User);
}
override getUserCredit(page?: string): Promise<{ credits: number }> {
return Promise.resolve({ credits: this.props.credits });
}
override getAutoTopUpConfig(): Promise<{
amount: number;
threshold: number;
}> {
return Promise.resolve({ amount: 10, threshold: 10 });
}
override setAutoTopUpConfig(config: {
amount: number;
threshold: number;
}): Promise<{ amount: number; threshold: number }> {
return Promise.resolve(config);
}
override requestTopUp(amount: number): Promise<{ checkout_url: string }> {
return Promise.resolve({ checkout_url: "https://checkout.stripe.com" });
}
override getUserPaymentPortalLink(): Promise<{ url: string }> {
return Promise.resolve({ url: "https://payment.stripe.com" });
}
override fulfillCheckout(): Promise<void> {
return Promise.resolve();
}
override getBlocks(): Promise<Block[]> {
return Promise.resolve(this.props.blocks);
}
override getStoreProfile(page?: string): Promise<ProfileDetails> {
return Promise.resolve(this.props.profile);
}
}

View File

@@ -1,6 +1,10 @@
import { User } from "@supabase/supabase-js";
import getServerSupabase from "./getServerSupabase";
const getServerUser = async () => {
const getServerUser = async (mockUser?: User) => {
if (mockUser) {
return { user: mockUser, role: "admin", error: null };
}
const supabase = getServerSupabase();
if (!supabase) {