mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-11 16:18:07 -05:00
Compare commits
61 Commits
feat/execu
...
ci-chromat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54bbafc431 | ||
|
|
5662783624 | ||
|
|
a5f448af98 | ||
|
|
c766bd66e1 | ||
|
|
6d11ad8051 | ||
|
|
d476983bd2 | ||
|
|
3ac1ce5a3f | ||
|
|
3b89e6d2b7 | ||
|
|
c7a7652b9f | ||
|
|
b6b0d0b209 | ||
|
|
a5b1495062 | ||
|
|
026f16c10f | ||
|
|
c468201c53 | ||
|
|
5beb581d1c | ||
|
|
df2339c1cf | ||
|
|
327db54321 | ||
|
|
234d6f78ba | ||
|
|
43088ddff8 | ||
|
|
fd955fba25 | ||
|
|
83943d9ddb | ||
|
|
60c26e62f6 | ||
|
|
1fc8f9ba66 | ||
|
|
33d747f457 | ||
|
|
06fa001a37 | ||
|
|
4e7b56b814 | ||
|
|
d6b03a4f18 | ||
|
|
fae9aeb49a | ||
|
|
5e8c1e274e | ||
|
|
55f7dc4853 | ||
|
|
b317adb9cf | ||
|
|
c873ba04b8 | ||
|
|
00f0311dd0 | ||
|
|
9b2bd756fa | ||
|
|
bceb83ca30 | ||
|
|
eadbfcd920 | ||
|
|
9768540b60 | ||
|
|
697436be07 | ||
|
|
d725e105a0 | ||
|
|
927f43f52f | ||
|
|
eedcc92d6f | ||
|
|
f0c378c70d | ||
|
|
c6c2b852df | ||
|
|
aaab8b1e0e | ||
|
|
a4eeb4535a | ||
|
|
db068c598c | ||
|
|
d4d9efc73e | ||
|
|
ffaf77df4e | ||
|
|
2daf08434e | ||
|
|
745137f4c2 | ||
|
|
3a2c3deb0e | ||
|
|
66a15a7b8c | ||
|
|
669c61de76 | ||
|
|
e860bde3d4 | ||
|
|
f5394f6d65 | ||
|
|
06e845abe7 | ||
|
|
c2c3c29018 | ||
|
|
31fd0b557a | ||
|
|
9350fe1d2b | ||
|
|
5ae92820b4 | ||
|
|
66a87e5a14 | ||
|
|
e1f8882e2d |
24
.github/workflows/platform-frontend-ci.yml
vendored
24
.github/workflows/platform-frontend-ci.yml
vendored
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user