mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix(frontend): fix all lint errors and add next/typescript (#10182)
## Changes 🏗️ ### ESLint Config 1. **Disabled `react-hooks/exhaustive-deps`:** - to prevent unnecessary dependency proliferation and rely on code review instead 2. **Added [`next/typescript`](https://nextjs.org/docs/app/api-reference/config/eslint#with-typescript):** - to the ESLint config to make sure we also have TS linting rules 3. **Added custom rule for `@typescript-eslint/no-unused-vars`:** - to allow underscore-prefixed variables (convention for intentionally unused), in some cases helpful From now on, whenever we have unused variables or imports, the `lint` CI will fail 🔴 , thanks to `next/typescript` that adds `typescript-eslint/no-unused-vars` 💆🏽 ### Minor Fixes - Replaced empty interfaces with type aliases to resolve `@typescript-eslint/no-empty-object-type` warnings - Fixed unsafe non-null assertions with proper null checks - Removed `@ts-ignore` comments in favour of proper type casting ( _when possible_ 🙏🏽 ) ### Google Analytics Component - Changed Next.js Script strategy from `beforeInteractive` to `afterInteractive` to resolve Next.js warnings - this make sure loading analytics does not block page render 🙏🏽 ( _better page load time_ ) ### Are these changes safe? As long as the Typescript compiler does not complain ( check the `type-check` job ) we should be save. Most changes are removing unused code, if that code would be used somewhere else the compiler should catch it and tell us 🫶 I also typed some code when possible, or bypassed the linter when I thought it was fair for now. I disabled a couple ESLint rules. Most importantly the `no-explicity-any` one as we have loads of stuff untyped yet ( _this should be improved once API types are generated for us_ ). ### DX Added some settings on `.vscode` folder 📁 so that files will be formatted on save and also ESLint will fix errors on save when able 💯 ### 📈 **Result:** - ✅ All linting errors resolved - ✅ Improved TypeScript strict mode compliance - ✅ Better developer experience with cleaner code ## Checklist 📋 #### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] Lint CI job passes - [x] There is not type errors ( _TS will catch issue related to these changes_ )
This commit is contained in:
@@ -1,3 +1,25 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "plugin:storybook/recommended"]
|
||||
"extends": [
|
||||
"next/core-web-vitals",
|
||||
"next/typescript",
|
||||
"plugin:storybook/recommended"
|
||||
],
|
||||
"rules": {
|
||||
// Disabling exhaustive-deps to avoid forcing unnecessary dependencies and useCallback proliferation.
|
||||
// We rely on code review for proper dependency management instead of mechanical rule following.
|
||||
// See: https://kentcdodds.com/blog/usememo-and-usecallback
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
// Disable temporarily as we have some `any` in the codebase and we need to got case by case
|
||||
// and see if they can be fixed.
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
// Allow unused vars that start with underscore (convention for intentionally unused)
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"caughtErrorsIgnorePattern": "^_"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
node_modules
|
||||
pnpm-lock.yaml
|
||||
.next
|
||||
.auth
|
||||
build
|
||||
public
|
||||
|
||||
@@ -9,7 +9,6 @@ import { OnboardingText } from "@/components/onboarding/OnboardingText";
|
||||
import { OnboardingGrid } from "@/components/onboarding/OnboardingGrid";
|
||||
import { useCallback } from "react";
|
||||
import OnboardingInput from "@/components/onboarding/OnboardingInput";
|
||||
import { isEmptyOrWhitespace } from "@/lib/utils";
|
||||
import { useOnboarding } from "@/components/onboarding/onboarding-provider";
|
||||
|
||||
const services = [
|
||||
|
||||
@@ -49,6 +49,7 @@ export default function Page() {
|
||||
.getAgentMetaByStoreListingVersionId(state?.selectedStoreListingVersionId)
|
||||
.then((agent) => {
|
||||
setAgent(agent);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const update: { [key: string]: any } = {};
|
||||
// Set default values from schema
|
||||
Object.entries(agent.input_schema.properties).forEach(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ShoppingBag } from "lucide-react";
|
||||
import { Sidebar } from "@/components/agptui/Sidebar";
|
||||
import { Users, DollarSign, LogOut } from "lucide-react";
|
||||
import { Users, DollarSign } from "lucide-react";
|
||||
|
||||
import { IconSliders } from "@/components/ui/icons";
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
import { revalidatePath } from "next/cache";
|
||||
import BackendApi from "@/lib/autogpt-server-api";
|
||||
import {
|
||||
NotificationPreferenceDTO,
|
||||
StoreListingsWithVersionsResponse,
|
||||
StoreSubmissionsResponse,
|
||||
SubmissionStatus,
|
||||
} from "@/lib/autogpt-server-api/types";
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ export async function getUsersTransactionHistory(
|
||||
search?: string,
|
||||
transactionType?: CreditTransactionType,
|
||||
): Promise<UsersBalanceHistoryResponse> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const data: Record<string, any> = {
|
||||
page,
|
||||
page_size: pageSize,
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function GET(request: Request) {
|
||||
return NextResponse.redirect(`${origin}/error`);
|
||||
}
|
||||
|
||||
const { data, error } = await supabase.auth.exchangeCodeForSession(code);
|
||||
const { error } = await supabase.auth.exchangeCodeForSession(code);
|
||||
// data.session?.refresh_token is available if you need to store it for later use
|
||||
if (!error) {
|
||||
try {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { NextResponse } from "next/server";
|
||||
// controlled by the CredentialsInput component. The CredentialsInput opens the login
|
||||
// page in a pop-up window, which then redirects to this route to close the loop.
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams, origin } = new URL(request.url);
|
||||
const { searchParams } = new URL(request.url);
|
||||
const code = searchParams.get("code");
|
||||
const state = searchParams.get("state");
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import BackendAPI from "@/lib/autogpt-server-api/client";
|
||||
import { OttoQuery, OttoResponse } from "@/lib/autogpt-server-api/types";
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ export default async function Page({
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return (
|
||||
<div className="flex h-screen w-full items-center justify-center">
|
||||
<div className="text-2xl text-neutral-900">Creator not found</div>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { SearchFilterChips } from "@/components/agptui/SearchFilterChips";
|
||||
import { SortDropdown } from "@/components/agptui/SortDropdown";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
import { Creator, StoreAgent } from "@/lib/autogpt-server-api";
|
||||
|
||||
type MarketplaceSearchPageSearchParams = { searchTerm?: string; sort?: string };
|
||||
|
||||
@@ -33,8 +34,8 @@ function SearchResults({
|
||||
}): React.ReactElement {
|
||||
const [showAgents, setShowAgents] = useState(true);
|
||||
const [showCreators, setShowCreators] = useState(true);
|
||||
const [agents, setAgents] = useState<any[]>([]);
|
||||
const [creators, setCreators] = useState<any[]>([]);
|
||||
const [agents, setAgents] = useState<StoreAgent[]>([]);
|
||||
const [creators, setCreators] = useState<Creator[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const api = useBackendAPI();
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
|
||||
export default function Page({}: {}) {
|
||||
export default function Page() {
|
||||
const { supabase } = useSupabase();
|
||||
const api = useBackendAPI();
|
||||
const [submissions, setSubmissions] = useState<StoreSubmissionsResponse>();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { Suspense } from "react";
|
||||
import React from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { fonts } from "@/components/styles/fonts";
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ export default function ConnectionLine<NodeType extends Node>({
|
||||
}: ConnectionLineComponentProps<NodeType>) {
|
||||
const sourceX =
|
||||
fromPosition === Position.Right
|
||||
? fromX + (fromHandle?.width! / 2 - 5)
|
||||
: fromX - (fromHandle?.width! / 2 - 5);
|
||||
? fromX + ((fromHandle?.width ?? 0) / 2 - 5)
|
||||
: fromX - ((fromHandle?.width ?? 0) / 2 - 5);
|
||||
|
||||
const [path] = getBezierPath({
|
||||
sourceX: sourceX,
|
||||
|
||||
@@ -93,7 +93,7 @@ export function CustomEdge({
|
||||
return;
|
||||
}
|
||||
|
||||
const beadUp = data?.beadUp!;
|
||||
const beadUp: number = data?.beadUp ?? 0;
|
||||
|
||||
// Add beads
|
||||
setBeads(({ beads, created, destroyed }) => {
|
||||
@@ -114,7 +114,7 @@ export function CustomEdge({
|
||||
const newBeads = beads
|
||||
.map((bead) => ({ ...bead }))
|
||||
.filter((bead, index) => {
|
||||
const beadDown = data?.beadDown!;
|
||||
const beadDown: number = data?.beadDown ?? 0;
|
||||
const removeCount = beadDown - destroyed;
|
||||
if (bead.t >= bead.targetT && index < removeCount) {
|
||||
destroyedCount++;
|
||||
@@ -151,7 +151,7 @@ export function CustomEdge({
|
||||
};
|
||||
})
|
||||
.filter((bead, index) => {
|
||||
const beadDown = data?.beadDown!;
|
||||
const beadDown: number = data?.beadDown ?? 0;
|
||||
const removeCount = beadDown - destroyed;
|
||||
if (bead.t >= bead.targetT && index < removeCount) {
|
||||
destroyedCount++;
|
||||
|
||||
@@ -95,13 +95,7 @@ export type CustomNodeData = {
|
||||
export type CustomNode = XYNode<CustomNodeData, "custom">;
|
||||
|
||||
export const CustomNode = React.memo(
|
||||
function CustomNode({
|
||||
data,
|
||||
id,
|
||||
width,
|
||||
height,
|
||||
selected,
|
||||
}: NodeProps<CustomNode>) {
|
||||
function CustomNode({ data, id, height, selected }: NodeProps<CustomNode>) {
|
||||
const [isOutputOpen, setIsOutputOpen] = useState(
|
||||
data.isOutputOpen || false,
|
||||
);
|
||||
@@ -199,10 +193,6 @@ export const CustomNode = React.memo(
|
||||
[id, updateNodeData],
|
||||
);
|
||||
|
||||
const toggleOutput = (checked: boolean) => {
|
||||
setIsOutputOpen(checked);
|
||||
};
|
||||
|
||||
const toggleAdvancedSettings = (checked: boolean) => {
|
||||
setIsAdvancedOpen(checked);
|
||||
};
|
||||
@@ -256,7 +246,7 @@ export const CustomNode = React.memo(
|
||||
nodeType: BlockUIType,
|
||||
) => {
|
||||
if (!schema?.properties) return null;
|
||||
let keys = Object.entries(schema.properties);
|
||||
const keys = Object.entries(schema.properties);
|
||||
switch (nodeType) {
|
||||
case BlockUIType.NOTE:
|
||||
// For NOTE blocks, don't render any input handles
|
||||
@@ -443,7 +433,7 @@ export const CustomNode = React.memo(
|
||||
// For primitive values, use the original string
|
||||
handleInputChange(activeKey, value);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// If JSON parsing fails, treat as plain text
|
||||
handleInputChange(activeKey, value);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import React from "react";
|
||||
import { beautifyString } from "@/lib/utils";
|
||||
import { Clipboard } from "lucide-react";
|
||||
import React from "react";
|
||||
import { Button } from "./ui/button";
|
||||
import { ContentRenderer } from "./ui/render";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -9,9 +11,7 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "./ui/table";
|
||||
import { Clipboard } from "lucide-react";
|
||||
import { useToast } from "./ui/use-toast";
|
||||
import { ContentRenderer } from "./ui/render";
|
||||
|
||||
type DataTableProps = {
|
||||
title?: string;
|
||||
@@ -25,7 +25,6 @@ export default function DataTable({
|
||||
data,
|
||||
}: DataTableProps) {
|
||||
const { toast } = useToast();
|
||||
const maxChars = 100;
|
||||
|
||||
const copyData = (pin: string, data: string) => {
|
||||
navigator.clipboard.writeText(data).then(() => {
|
||||
|
||||
@@ -90,9 +90,7 @@ const FlowEditor: React.FC<{
|
||||
} = useReactFlow<CustomNode, CustomEdge>();
|
||||
const [nodeId, setNodeId] = useState<number>(1);
|
||||
const [isAnyModalOpen, setIsAnyModalOpen] = useState(false);
|
||||
const [visualizeBeads, setVisualizeBeads] = useState<
|
||||
"no" | "static" | "animate"
|
||||
>("animate");
|
||||
const [visualizeBeads] = useState<"no" | "static" | "animate">("animate");
|
||||
const [flowExecutionID, setFlowExecutionID] = useState<
|
||||
GraphExecutionID | undefined
|
||||
>();
|
||||
@@ -366,10 +364,7 @@ const FlowEditor: React.FC<{
|
||||
replaceEdges = edgeChanges.filter(
|
||||
(change) => change.type === "replace",
|
||||
),
|
||||
removedEdges = edgeChanges.filter((change) => change.type === "remove"),
|
||||
selectedEdges = edgeChanges.filter(
|
||||
(change) => change.type === "select",
|
||||
);
|
||||
removedEdges = edgeChanges.filter((change) => change.type === "remove");
|
||||
|
||||
if (addedEdges.length > 0 || removedEdges.length > 0) {
|
||||
setNodes((nds) => {
|
||||
|
||||
@@ -212,7 +212,7 @@ export default function OttoChatWidget({
|
||||
<p className="mb-2 last:mb-0">{children}</p>
|
||||
),
|
||||
code(props) {
|
||||
const { children, className, node, ...rest } = props;
|
||||
const { children, className, node: _, ...rest } = props;
|
||||
const match = /language-(\w+)/.exec(className || "");
|
||||
return match ? (
|
||||
<pre className="overflow-x-auto rounded-md bg-muted-foreground/20 p-3">
|
||||
|
||||
@@ -22,7 +22,7 @@ const SchemaTooltip: React.FC<{ description?: string }> = ({ description }) => {
|
||||
<TooltipContent className="tooltip-content max-w-xs bg-white text-gray-900 dark:bg-gray-800 dark:text-gray-100">
|
||||
<ReactMarkdown
|
||||
components={{
|
||||
a: ({ node, ...props }) => (
|
||||
a: ({ node: _, ...props }) => (
|
||||
<a
|
||||
target="_blank"
|
||||
className="text-blue-400 underline dark:text-blue-300"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { Text, textVariants, type TextVariant } from "./Text";
|
||||
import { Text, textVariants } from "./Text";
|
||||
import { StoryCode } from "@/stories/helpers/StoryCode";
|
||||
|
||||
const meta: Meta<typeof Text> = {
|
||||
|
||||
@@ -9,9 +9,8 @@ import {
|
||||
TableHead,
|
||||
TableBody,
|
||||
} from "@/components/ui/table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ChevronDown, ChevronRight, ExternalLink } from "lucide-react";
|
||||
import { ChevronDown, ChevronRight } from "lucide-react";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
import {
|
||||
type StoreListingWithVersions,
|
||||
@@ -19,7 +18,6 @@ import {
|
||||
SubmissionStatus,
|
||||
} from "@/lib/autogpt-server-api/types";
|
||||
import { ApproveRejectButtons } from "./approve-reject-buttons";
|
||||
import { downloadAsAdmin } from "@/app/(platform)/admin/marketplace/actions";
|
||||
import { DownloadAgentAdminButton } from "./download-agent-button";
|
||||
|
||||
// Moved the getStatusBadge function into the client component
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
import { SubmissionStatus } from "@/lib/autogpt-server-api/types";
|
||||
|
||||
export function SearchAndFilterAdminMarketplace({
|
||||
initialStatus,
|
||||
initialSearch,
|
||||
}: {
|
||||
initialStatus?: SubmissionStatus;
|
||||
|
||||
@@ -15,7 +15,6 @@ import { Textarea } from "@/components/ui/textarea";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { addDollars } from "@/app/(platform)/admin/spending/actions";
|
||||
import useCredits from "@/hooks/useCredits";
|
||||
|
||||
export function AdminAddMoneyButton({
|
||||
userId,
|
||||
@@ -36,8 +35,6 @@ export function AdminAddMoneyButton({
|
||||
defaultAmount ? Math.abs(defaultAmount / 100).toFixed(2) : "1.00",
|
||||
);
|
||||
|
||||
const { formatCredits } = useCredits();
|
||||
|
||||
const handleApproveSubmit = async (formData: FormData) => {
|
||||
setIsAddMoneyDialogOpen(false);
|
||||
try {
|
||||
|
||||
@@ -48,7 +48,7 @@ export async function AdminUserGrantHistory({
|
||||
const isPurchased = type === CreditTransactionType.TOP_UP;
|
||||
const isSpent = type === CreditTransactionType.USAGE;
|
||||
|
||||
let displayText = type;
|
||||
const displayText = type;
|
||||
let bgColor = "";
|
||||
|
||||
if (isGrant) {
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
} from "@/components/ui/select";
|
||||
|
||||
export function SearchAndFilterAdminSpending({
|
||||
initialStatus,
|
||||
initialSearch,
|
||||
}: {
|
||||
initialStatus?: CreditTransactionType;
|
||||
@@ -74,7 +73,7 @@ export function SearchAndFilterAdminSpending({
|
||||
|
||||
<Select
|
||||
value={selectedStatus}
|
||||
onValueChange={(value) => {
|
||||
onValueChange={(value: string) => {
|
||||
setSelectedStatus(value);
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
if (value === "ALL") {
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { AgentTable } from "./AgentTable";
|
||||
import { AgentTableRowProps } from "./AgentTableRow";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
import { StatusType } from "./Status";
|
||||
|
||||
const meta: Meta<typeof AgentTable> = {
|
||||
title: "AGPT UI/Agent Table",
|
||||
@@ -104,6 +103,6 @@ export const EmptyTableTest: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const emptyMessage = canvas.getByText("No agents found");
|
||||
expect(emptyMessage).toBeTruthy();
|
||||
await expect(emptyMessage).toBeTruthy();
|
||||
},
|
||||
};
|
||||
|
||||
@@ -90,7 +90,7 @@ export const AgentTable: React.FC<AgentTableProps> = ({
|
||||
{/* Table body */}
|
||||
{agents.length > 0 ? (
|
||||
<div className="flex flex-col">
|
||||
{agents.map((agent, index) => (
|
||||
{agents.map((agent) => (
|
||||
<div key={agent.id} className="md:block">
|
||||
<AgentTableRow
|
||||
{...agent}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { AgentTableCard } from "./AgentTableCard";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
import { type StatusType } from "./Status";
|
||||
|
||||
const meta: Meta<typeof AgentTableCard> = {
|
||||
|
||||
@@ -32,7 +32,6 @@ export const AgentTableCard: React.FC<AgentTableCardProps> = ({
|
||||
status,
|
||||
runs,
|
||||
rating,
|
||||
id,
|
||||
onEditSubmission,
|
||||
}) => {
|
||||
const onEdit = () => {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import * as React from "react";
|
||||
import Link from "next/link";
|
||||
import { IconLeftArrow, IconRightArrow } from "@/components/ui/icons";
|
||||
|
||||
interface BreadcrumbItem {
|
||||
name: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { FeaturedAgentCard } from "./FeaturedAgentCard";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
import { FeaturedAgentCard } from "./FeaturedAgentCard";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Featured Store Card",
|
||||
@@ -35,6 +35,7 @@ type Story = StoryObj<typeof meta>;
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
agent: {
|
||||
updated_at: "2024-01-10T15:30:00.000Z",
|
||||
agent_name:
|
||||
"Personalized Morning Coffee Newsletter example of three lines",
|
||||
sub_heading:
|
||||
@@ -57,6 +58,7 @@ export const Default: Story = {
|
||||
export const WithInteraction: Story = {
|
||||
args: {
|
||||
agent: {
|
||||
updated_at: "2024-01-10T15:30:00.000Z",
|
||||
slug: "",
|
||||
agent_name: "AI Writing Assistant",
|
||||
sub_heading: "Enhance your writing",
|
||||
|
||||
@@ -46,7 +46,7 @@ export const WithSelectedFilters: Story = {
|
||||
badges: defaultBadges,
|
||||
multiSelect: true,
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const marketingChip = canvas.getByText("Marketing").parentElement;
|
||||
const salesChip = canvas.getByText("Sales").parentElement;
|
||||
@@ -70,7 +70,7 @@ export const WithFilterChangeCallback: Story = {
|
||||
console.log("Selected filters:", selectedFilters);
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const salesChip = canvas.getByText("Sales");
|
||||
const marketingChip = canvas.getByText("Marketing");
|
||||
@@ -104,7 +104,7 @@ export const SingleSelectBehavior: Story = {
|
||||
badges: defaultBadges,
|
||||
multiSelect: false,
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const salesChip = canvas.getByText("Sales").parentElement;
|
||||
const marketingChip = canvas.getByText("Marketing").parentElement;
|
||||
|
||||
@@ -2,32 +2,6 @@ import type { Meta, StoryObj } from "@storybook/react";
|
||||
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 = {
|
||||
name: "John Doe",
|
||||
username: "johndoe",
|
||||
description: "",
|
||||
links: [],
|
||||
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",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
"use client";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { IconLogOut } from "@/components/ui/icons";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
import { cn } from "@/lib/utils";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useTransition } from "react";
|
||||
import { LoadingSpinner } from "../ui/loading";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { toast } from "../ui/use-toast";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
|
||||
export function ProfilePopoutMenuLogoutButton() {
|
||||
const router = useRouter();
|
||||
@@ -16,7 +16,7 @@ export function ProfilePopoutMenuLogoutButton() {
|
||||
function handleLogout() {
|
||||
startTransition(async () => {
|
||||
try {
|
||||
await supabase.logOut({ scope: "global" });
|
||||
await supabase.logOut();
|
||||
router.refresh();
|
||||
} catch (e) {
|
||||
Sentry.captureException(e);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { StoreCard } from "./StoreCard";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/StoreCard",
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import * as React from "react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { IconMoon, IconSun } from "@/components/ui/icons";
|
||||
import { Button } from "./Button";
|
||||
|
||||
export function ThemeToggle() {
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
@@ -60,7 +60,6 @@ export default function WalletRefill() {
|
||||
|
||||
// Pre-fill the auto-refill form with existing values
|
||||
useEffect(() => {
|
||||
const values = autoRefillForm.getValues();
|
||||
if (
|
||||
autoTopUpConfig &&
|
||||
autoTopUpConfig.amount > 0 &&
|
||||
|
||||
@@ -84,7 +84,7 @@ export function APIKeysSection() {
|
||||
setIsCreateOpen(false);
|
||||
setIsKeyDialogOpen(true);
|
||||
loadAPIKeys();
|
||||
} catch (error) {
|
||||
} catch {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to create AutoGPT Platform API key",
|
||||
@@ -109,7 +109,7 @@ export function APIKeysSection() {
|
||||
description: "AutoGPT Platform API key revoked successfully",
|
||||
});
|
||||
loadAPIKeys();
|
||||
} catch (error) {
|
||||
} catch {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to revoke AutoGPT Platform API key",
|
||||
@@ -168,7 +168,7 @@ export function APIKeysSection() {
|
||||
<Checkbox
|
||||
id={permission}
|
||||
checked={selectedPermissions.includes(permission)}
|
||||
onCheckedChange={(checked) => {
|
||||
onCheckedChange={(checked: boolean) => {
|
||||
setSelectedPermissions(
|
||||
checked
|
||||
? [...selectedPermissions, permission]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { FeaturedSection } from "./FeaturedSection";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
import { StoreAgent } from "@/lib/autogpt-server-api";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
import { FeaturedSection } from "./FeaturedSection";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Composite/Featured Agents",
|
||||
@@ -24,6 +24,7 @@ type Story = StoryObj<typeof meta>;
|
||||
|
||||
const mockFeaturedAgents = [
|
||||
{
|
||||
updated_at: "2024-01-10T15:30:00.000Z",
|
||||
agent_name: "Personalized Morning Coffee Newsletter example of three lines",
|
||||
sub_heading:
|
||||
"Transform ideas into breathtaking images with this AI-powered Image Generator.",
|
||||
@@ -39,6 +40,7 @@ const mockFeaturedAgents = [
|
||||
slug: "personalized-morning-coffee-newsletter",
|
||||
},
|
||||
{
|
||||
updated_at: "2024-01-10T15:30:00.000Z",
|
||||
agent_name: "Data Analyzer Lite",
|
||||
sub_heading: "Basic data analysis tool",
|
||||
creator: "DataTech",
|
||||
@@ -53,6 +55,7 @@ const mockFeaturedAgents = [
|
||||
slug: "data-analyzer-lite",
|
||||
},
|
||||
{
|
||||
updated_at: "2024-01-10T15:30:00.000Z",
|
||||
agent_name: "CodeAssist AI",
|
||||
sub_heading: "Your AI coding companion",
|
||||
creator: "DevTools Co.",
|
||||
@@ -67,6 +70,7 @@ const mockFeaturedAgents = [
|
||||
slug: "codeassist-ai",
|
||||
},
|
||||
{
|
||||
updated_at: "2024-01-10T15:30:00.000Z",
|
||||
agent_name: "MultiTasker",
|
||||
sub_heading: "All-in-one productivity suite",
|
||||
creator: "Productivity Plus",
|
||||
@@ -81,6 +85,7 @@ const mockFeaturedAgents = [
|
||||
slug: "multitasker",
|
||||
},
|
||||
{
|
||||
updated_at: "2024-01-10T15:30:00.000Z",
|
||||
agent_name: "QuickTask",
|
||||
sub_heading: "Fast task automation",
|
||||
creator: "EfficientWorks",
|
||||
|
||||
@@ -27,7 +27,7 @@ interface FeaturedSectionProps {
|
||||
export const FeaturedSection: React.FC<FeaturedSectionProps> = ({
|
||||
featuredAgents,
|
||||
}) => {
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
const [_, setCurrentSlide] = useState(0);
|
||||
|
||||
const handlePrevSlide = useCallback(() => {
|
||||
setCurrentSlide((prev) =>
|
||||
|
||||
@@ -5,7 +5,6 @@ import { SearchBar } from "@/components/agptui/SearchBar";
|
||||
import { FilterChips } from "@/components/agptui/FilterChips";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useOnboarding } from "@/components/onboarding/onboarding-provider";
|
||||
import { useSupabase } from "@/lib/supabase/hooks/useSupabase";
|
||||
|
||||
export const HeroSection: React.FC = () => {
|
||||
const router = useRouter();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { PublishAgentPopout } from "@/components/agptui/composite/PublishAgentPopout";
|
||||
import { userEvent, within, expect } from "@storybook/test";
|
||||
import { userEvent, within } from "@storybook/test";
|
||||
|
||||
const meta = {
|
||||
title: "AGPT UI/Composite/Publish Agent Popout",
|
||||
|
||||
@@ -47,7 +47,7 @@ export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
|
||||
inputStep,
|
||||
);
|
||||
const [myAgents, setMyAgents] = React.useState<MyAgentsResponse | null>(null);
|
||||
const [selectedAgent, setSelectedAgent] = React.useState<string | null>(null);
|
||||
const [_, setSelectedAgent] = React.useState<string | null>(null);
|
||||
const [initialData, setInitialData] =
|
||||
React.useState<PublishAgentInfoInitialData>({
|
||||
agent_id: "",
|
||||
@@ -181,7 +181,7 @@ export const PublishAgentPopout: React.FC<PublishAgentPopoutProps> = ({
|
||||
|
||||
// Create store submission
|
||||
try {
|
||||
const submission = await api.createStoreSubmission({
|
||||
await api.createStoreSubmission({
|
||||
name: name,
|
||||
sub_heading: subHeading,
|
||||
description: description,
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import Script from "next/script";
|
||||
import type { GAParams } from "@/types/google";
|
||||
import Script from "next/script";
|
||||
import { useEffect } from "react";
|
||||
|
||||
let currDataLayerName: string | undefined = undefined;
|
||||
|
||||
@@ -31,7 +31,8 @@ export function GoogleAnalytics(props: GAParams) {
|
||||
<>
|
||||
<Script
|
||||
id="_custom-ga-init"
|
||||
strategy="beforeInteractive"
|
||||
// Using "afterInteractive" to avoid blocking the initial page rendering
|
||||
strategy="afterInteractive"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
window['${dataLayerName}'] = window['${dataLayerName}'] || [];
|
||||
@@ -44,7 +45,7 @@ export function GoogleAnalytics(props: GAParams) {
|
||||
/>
|
||||
<Script
|
||||
id="_custom-ga"
|
||||
strategy="beforeInteractive"
|
||||
strategy="afterInteractive"
|
||||
src="/gtag.js"
|
||||
nonce={nonce}
|
||||
/>
|
||||
@@ -52,15 +53,15 @@ export function GoogleAnalytics(props: GAParams) {
|
||||
);
|
||||
}
|
||||
|
||||
export function sendGAEvent(..._args: any[]) {
|
||||
export function sendGAEvent(...args: any[]) {
|
||||
if (currDataLayerName === undefined) {
|
||||
console.warn(`Custom GA: GA has not been initialized`);
|
||||
return;
|
||||
}
|
||||
//@ts-ignore
|
||||
if (window[currDataLayerName]) {
|
||||
//@ts-ignore
|
||||
window[currDataLayerName].push(arguments);
|
||||
|
||||
const dataLayer = (window as any)[currDataLayerName];
|
||||
if (dataLayer) {
|
||||
dataLayer.push(...args);
|
||||
} else {
|
||||
console.warn(`Custom GA: dataLayer ${currDataLayerName} does not exist`);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AlertCircle, CheckCircle } from "lucide-react";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { HelpItem } from "@/components/auth/help-item";
|
||||
import { BehaveAs } from "@/lib/utils";
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useState } from "react";
|
||||
import { FaGoogle, FaSpinner } from "react-icons/fa";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export interface TurnstileProps {
|
||||
siteKey: string;
|
||||
@@ -120,7 +120,7 @@ export function Turnstile({
|
||||
]);
|
||||
|
||||
// Method to reset the widget manually
|
||||
const reset = useCallback(() => {
|
||||
useEffect(() => {
|
||||
if (loaded && widgetIdRef.current && window.turnstile && shouldRender) {
|
||||
window.turnstile.reset(widgetIdRef.current);
|
||||
}
|
||||
|
||||
@@ -9,12 +9,7 @@ import {
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Separator } from "./ui/separator";
|
||||
import { CronExpressionManager } from "@/lib/monitor/cronExpressionManager";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import LibraryUploadAgentDialog from "./library-upload-agent-dialog";
|
||||
import LibrarySearchBar from "./library-search-bar";
|
||||
|
||||
interface LibraryActionHeaderProps {}
|
||||
type LibraryActionHeaderProps = Record<string, never>;
|
||||
|
||||
/**
|
||||
* LibraryActionHeader component - Renders a header with search, notifications and filters
|
||||
|
||||
@@ -24,7 +24,7 @@ interface NotificationCardProps {
|
||||
}
|
||||
|
||||
const NotificationCard = ({
|
||||
notification: { id, type, title, content, mediaUrl },
|
||||
notification: { type, title, content, mediaUrl },
|
||||
onClose,
|
||||
}: NotificationCardProps) => {
|
||||
const barHeights = Array.from({ length: 60 }, () =>
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function LibrarySortMenu(): React.ReactNode {
|
||||
setLibrarySort(value);
|
||||
setAgentLoading(true);
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
let response = await api.listLibraryAgents({
|
||||
const response = await api.listLibraryAgents({
|
||||
search_term: searchTerm,
|
||||
sort_by: value,
|
||||
page: 1,
|
||||
|
||||
@@ -35,7 +35,6 @@ import {
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
} from "@/components/ui/dialog";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import RunnerInputUI from "@/components/runner-ui/RunnerInputUI";
|
||||
import useAgentGraph from "@/hooks/useAgentGraph";
|
||||
import { useBackendAPI } from "@/lib/autogpt-server-api/context";
|
||||
@@ -52,7 +51,6 @@ export const FlowInfo: React.FC<
|
||||
useAgentGraph(flow.graph_id, flow.graph_version, undefined, false);
|
||||
|
||||
const api = useBackendAPI();
|
||||
const { toast } = useToast();
|
||||
|
||||
const [flowVersions, setFlowVersions] = useState<Graph[] | null>(null);
|
||||
const [selectedVersion, setSelectedFlowVersion] = useState(
|
||||
@@ -170,7 +168,7 @@ export const FlowInfo: React.FC<
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuRadioGroup
|
||||
value={String(selectedVersion)}
|
||||
onValueChange={(choice) =>
|
||||
onValueChange={(choice: string) =>
|
||||
setSelectedFlowVersion(
|
||||
choice == "all" ? choice : Number(choice),
|
||||
)
|
||||
|
||||
@@ -58,7 +58,7 @@ export const FlowRunsTimeline = ({
|
||||
tickFormatter={(s) => (s > 90 ? `${Math.round(s / 60)}m` : `${s}s`)}
|
||||
/>
|
||||
<Tooltip
|
||||
content={({ payload, label }) => {
|
||||
content={({ payload }) => {
|
||||
if (payload && payload.length) {
|
||||
const data: GraphExecutionMeta & {
|
||||
time: number;
|
||||
|
||||
@@ -77,7 +77,6 @@ const NodeObjectInputTree: FC<NodeObjectInputTreeProps> = ({
|
||||
handleInputChange,
|
||||
errors,
|
||||
className,
|
||||
displayName,
|
||||
}) => {
|
||||
object ||= ("default" in schema ? schema.default : null) ?? {};
|
||||
return (
|
||||
@@ -126,12 +125,10 @@ const NodeDateTimeInput: FC<{
|
||||
hideTime?: boolean;
|
||||
}> = ({
|
||||
selfKey,
|
||||
schema,
|
||||
value = "",
|
||||
error,
|
||||
handleInputChange,
|
||||
className,
|
||||
displayName,
|
||||
hideDate = false,
|
||||
hideTime = false,
|
||||
}) => {
|
||||
@@ -219,7 +216,6 @@ const NodeFileInput: FC<{
|
||||
displayName: string;
|
||||
}> = ({
|
||||
selfKey,
|
||||
schema,
|
||||
value = "",
|
||||
error,
|
||||
handleInputChange,
|
||||
@@ -279,7 +275,7 @@ const NodeFileInput: FC<{
|
||||
variant="ghost"
|
||||
className="text-red-500 hover:text-red-700"
|
||||
onClick={() => {
|
||||
inputRef.current && (inputRef.current!.value = "");
|
||||
if (inputRef.current) inputRef.current.value = "";
|
||||
handleInputChange(selfKey, "");
|
||||
}}
|
||||
>
|
||||
@@ -884,13 +880,6 @@ const NodeKeyValueInput: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
// Checking if schema is type of string
|
||||
function isStringSubSchema(
|
||||
schema: BlockIOSimpleTypeSubSchema,
|
||||
): schema is BlockIOStringSubSchema {
|
||||
return "type" in schema && schema.type === "string";
|
||||
}
|
||||
|
||||
const NodeArrayInput: FC<{
|
||||
nodeId: string;
|
||||
selfKey: string;
|
||||
@@ -1229,15 +1218,7 @@ const NodeBooleanInput: FC<{
|
||||
handleInputChange: NodeObjectInputTreeProps["handleInputChange"];
|
||||
className?: string;
|
||||
displayName: string;
|
||||
}> = ({
|
||||
selfKey,
|
||||
schema,
|
||||
value,
|
||||
error,
|
||||
handleInputChange,
|
||||
className,
|
||||
displayName,
|
||||
}) => {
|
||||
}> = ({ selfKey, schema, value, error, handleInputChange, className }) => {
|
||||
value ||= schema.default ?? false;
|
||||
return (
|
||||
<div className={className}>
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Link from "next/link";
|
||||
import { set } from "lodash";
|
||||
|
||||
const OnboardingContext = createContext<
|
||||
| {
|
||||
|
||||
@@ -20,10 +20,7 @@ import { Switch } from "@/components/ui/switch";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import { updateSettings } from "@/app/(platform)/profile/(user)/settings/actions";
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
import {
|
||||
NotificationPreference,
|
||||
NotificationPreferenceDTO,
|
||||
} from "@/lib/autogpt-server-api";
|
||||
import { NotificationPreferenceDTO } from "@/lib/autogpt-server-api";
|
||||
|
||||
const formSchema = z
|
||||
.object({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import React from "react";
|
||||
import {
|
||||
Sheet,
|
||||
SheetContent,
|
||||
|
||||
@@ -91,7 +91,7 @@ export const TypeBasedInput: FC<
|
||||
<Switch
|
||||
className="ml-auto"
|
||||
checked={!!value}
|
||||
onCheckedChange={(checked) => onChange(checked)}
|
||||
onCheckedChange={(checked: boolean) => onChange(checked)}
|
||||
{...props}
|
||||
/>
|
||||
</>
|
||||
@@ -145,7 +145,10 @@ export const TypeBasedInput: FC<
|
||||
schema.enum.length > 0
|
||||
) {
|
||||
innerInputElement = (
|
||||
<Select value={value ?? ""} onValueChange={(val) => onChange(val)}>
|
||||
<Select
|
||||
value={value ?? ""}
|
||||
onValueChange={(val: string) => onChange(val)}
|
||||
>
|
||||
<SelectTrigger
|
||||
className={cn(
|
||||
inputClasses,
|
||||
@@ -253,7 +256,7 @@ export function TimePicker({ value, onChange }: TimePickerProps) {
|
||||
<div className="flex flex-col items-center">
|
||||
<Select
|
||||
value={hour}
|
||||
onValueChange={(val) => changeTime(val, minute, meridiem)}
|
||||
onValueChange={(val: string) => changeTime(val, minute, meridiem)}
|
||||
>
|
||||
<SelectTrigger
|
||||
className={cn("agpt-border-input ml-1 text-center", inputClasses)}
|
||||
@@ -277,7 +280,7 @@ export function TimePicker({ value, onChange }: TimePickerProps) {
|
||||
<div className="flex flex-col items-center">
|
||||
<Select
|
||||
value={minute}
|
||||
onValueChange={(val) => changeTime(hour, val, meridiem)}
|
||||
onValueChange={(val: string) => changeTime(hour, val, meridiem)}
|
||||
>
|
||||
<SelectTrigger
|
||||
className={cn("agpt-border-input text-center", inputClasses)}
|
||||
@@ -297,7 +300,7 @@ export function TimePicker({ value, onChange }: TimePickerProps) {
|
||||
<div className="flex flex-col items-center">
|
||||
<Select
|
||||
value={meridiem}
|
||||
onValueChange={(val) => changeTime(hour, minute, val)}
|
||||
onValueChange={(val: string) => changeTime(hour, minute, val)}
|
||||
>
|
||||
<SelectTrigger
|
||||
className={cn("agpt-border-input text-center", inputClasses)}
|
||||
@@ -357,12 +360,7 @@ interface FileInputProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const FileInput: FC<FileInputProps> = ({
|
||||
value,
|
||||
placeholder,
|
||||
onChange,
|
||||
className,
|
||||
}) => {
|
||||
const FileInput: FC<FileInputProps> = ({ value, onChange, className }) => {
|
||||
const loadFile = (file: File) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
@@ -402,7 +400,7 @@ const FileInput: FC<FileInputProps> = ({
|
||||
<Cross2Icon
|
||||
className="h-5 w-5 cursor-pointer text-black"
|
||||
onClick={() => {
|
||||
inputRef.current && (inputRef.current.value = "");
|
||||
if (inputRef.current) inputRef.current.value = "";
|
||||
onChange("");
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -123,7 +123,6 @@ export const Sizes: Story = {
|
||||
const canvas = within(canvasElement);
|
||||
const buttons = canvas.getAllByRole("button");
|
||||
await expect(buttons).toHaveLength(5);
|
||||
const sizes = ["sm", "default", "lg", "primary", "icon"];
|
||||
const sizeClasses = [
|
||||
"h-8 rounded-md px-3 text-xs",
|
||||
"h-9 px-4 py-2",
|
||||
|
||||
@@ -23,7 +23,9 @@ const Command = React.forwardRef<
|
||||
));
|
||||
Command.displayName = CommandPrimitive.displayName;
|
||||
|
||||
interface CommandDialogProps extends DialogProps {}
|
||||
interface CommandDialogProps extends DialogProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||
return (
|
||||
|
||||
@@ -1842,11 +1842,10 @@ export function getIconForSocial(
|
||||
url: string,
|
||||
props: IconProps,
|
||||
): React.ReactNode {
|
||||
const lowerCaseUrl = url.toLowerCase();
|
||||
let host;
|
||||
try {
|
||||
host = new URL(url).host;
|
||||
} catch (e) {
|
||||
} catch {
|
||||
return <IconGlobe {...props} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@ import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
|
||||
@@ -56,7 +56,7 @@ export const Default: Story = {
|
||||
render: (args) => <MultiSelectorExample {...args} />,
|
||||
args: {
|
||||
values: [],
|
||||
onValuesChange: (value: string[]) => {},
|
||||
onValuesChange: () => {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -64,7 +64,7 @@ export const WithLoop: Story = {
|
||||
render: (args) => <MultiSelectorExample {...args} />,
|
||||
args: {
|
||||
values: [],
|
||||
onValuesChange: (value: string[]) => {},
|
||||
onValuesChange: () => {},
|
||||
loop: true,
|
||||
},
|
||||
};
|
||||
@@ -73,7 +73,7 @@ export const WithInitialValues: Story = {
|
||||
render: (args) => <MultiSelectorExample {...args} />,
|
||||
args: {
|
||||
values: ["apple", "banana"],
|
||||
onValuesChange: (value: string[]) => {},
|
||||
onValuesChange: () => {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -98,6 +98,6 @@ export const WithDisabledItem: Story = {
|
||||
),
|
||||
args: {
|
||||
values: [],
|
||||
onValuesChange: (value: string[]) => {},
|
||||
onValuesChange: () => {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ const meta = {
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
const PopoverExample = (args: any) => (
|
||||
const PopoverExample = () => (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline">Open Popover</Button>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import { ContentRenderer } from "./render";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import Image from "next/image";
|
||||
|
||||
const getYouTubeVideoId = (url: string) => {
|
||||
const regExp =
|
||||
|
||||
@@ -2,8 +2,7 @@ import * as React from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface TextareaProps
|
||||
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
|
||||
export type TextareaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement>;
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, ...props }, ref) => {
|
||||
|
||||
@@ -16,12 +16,12 @@ type ToasterToast = ToastProps & {
|
||||
dismissable?: boolean;
|
||||
};
|
||||
|
||||
const actionTypes = {
|
||||
ADD_TOAST: "ADD_TOAST",
|
||||
UPDATE_TOAST: "UPDATE_TOAST",
|
||||
DISMISS_TOAST: "DISMISS_TOAST",
|
||||
REMOVE_TOAST: "REMOVE_TOAST",
|
||||
} as const;
|
||||
type ActionTypes = {
|
||||
ADD_TOAST: "ADD_TOAST";
|
||||
UPDATE_TOAST: "UPDATE_TOAST";
|
||||
DISMISS_TOAST: "DISMISS_TOAST";
|
||||
REMOVE_TOAST: "REMOVE_TOAST";
|
||||
};
|
||||
|
||||
let count = 0;
|
||||
|
||||
@@ -30,7 +30,7 @@ function genId() {
|
||||
return count.toString();
|
||||
}
|
||||
|
||||
type ActionType = typeof actionTypes;
|
||||
type ActionType = ActionTypes;
|
||||
|
||||
type Action =
|
||||
| {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { CustomEdge } from "@/components/CustomEdge";
|
||||
import { CustomNode } from "@/components/CustomNode";
|
||||
import { useOnboarding } from "@/components/onboarding/onboarding-provider";
|
||||
import { InputItem } from "@/components/RunnerUIWrapper";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import BackendAPI, {
|
||||
Block,
|
||||
BlockIOSubSchema,
|
||||
@@ -8,6 +11,7 @@ import BackendAPI, {
|
||||
Graph,
|
||||
GraphExecutionID,
|
||||
GraphID,
|
||||
GraphMeta,
|
||||
NodeExecutionResult,
|
||||
SpecialBlockID,
|
||||
} from "@/lib/autogpt-server-api";
|
||||
@@ -19,13 +23,9 @@ import {
|
||||
} from "@/lib/utils";
|
||||
import { MarkerType } from "@xyflow/react";
|
||||
import Ajv from "ajv";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useRouter, useSearchParams, usePathname } from "next/navigation";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { InputItem } from "@/components/RunnerUIWrapper";
|
||||
import { GraphMeta } from "@/lib/autogpt-server-api";
|
||||
import { default as NextLink } from "next/link";
|
||||
import { useOnboarding } from "@/components/onboarding/onboarding-provider";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
const ajv = new Ajv({ strict: false, allErrors: true });
|
||||
|
||||
@@ -279,9 +279,6 @@ export default function useAgentGraph(
|
||||
const cleanupSourceName = (sourceName: string) =>
|
||||
isToolSourceName(sourceName) ? "tools" : sourceName;
|
||||
|
||||
const getToolArgName = (sourceName: string) =>
|
||||
isToolSourceName(sourceName) ? sourceName.split("_~_")[1] : null;
|
||||
|
||||
const getToolFuncName = (nodeId: string) => {
|
||||
const sinkNode = nodes.find((node) => node.id === nodeId);
|
||||
const sinkNodeName = sinkNode
|
||||
@@ -312,7 +309,7 @@ export default function useAgentGraph(
|
||||
new Map<string, NodeExecutionResult["status"]>();
|
||||
|
||||
// Update execution status for input edges
|
||||
for (let key in executionData.input_data) {
|
||||
for (const key in executionData.input_data) {
|
||||
if (
|
||||
edge.target !== getFrontendId(executionData.node_id, nodes) ||
|
||||
edge.targetHandle !== key
|
||||
@@ -328,7 +325,7 @@ export default function useAgentGraph(
|
||||
let beadUp = 0;
|
||||
let beadDown = 0;
|
||||
|
||||
execStatus.forEach((status) => {
|
||||
execStatus.forEach((status: NodeExecutionResult["status"]) => {
|
||||
beadUp++;
|
||||
if (status !== "INCOMPLETE") {
|
||||
// Count any non-incomplete execution as consumed
|
||||
@@ -831,7 +828,7 @@ export default function useAgentGraph(
|
||||
return inputData;
|
||||
};
|
||||
|
||||
let inputData = getNestedData(blockSchema, node.data.hardcodedValues);
|
||||
const inputData = getNestedData(blockSchema, node.data.hardcodedValues);
|
||||
|
||||
console.debug(
|
||||
`Final prepared input for ${node.data.blockType} (${node.id}):`,
|
||||
@@ -904,7 +901,6 @@ export default function useAgentGraph(
|
||||
});
|
||||
|
||||
const payload = {
|
||||
id: savedAgent?.id!,
|
||||
name: agentName || `New Agent ${new Date().toISOString()}`,
|
||||
description: agentDescription || "",
|
||||
nodes: formattedNodes,
|
||||
@@ -914,11 +910,15 @@ export default function useAgentGraph(
|
||||
// To avoid saving the same graph, we compare the payload with the saved agent.
|
||||
// Differences in IDs are ignored.
|
||||
const comparedPayload = {
|
||||
...(({ id, ...rest }) => rest)(payload),
|
||||
name: payload.name,
|
||||
description: payload.description,
|
||||
nodes: payload.nodes.map(
|
||||
({ id, data, input_nodes, output_nodes, ...rest }) => rest,
|
||||
({ id: _, data: __, input_nodes: ___, output_nodes: ____, ...rest }) =>
|
||||
rest,
|
||||
),
|
||||
links: payload.links.map(
|
||||
({ source_id: _, sink_id: __, ...rest }) => rest,
|
||||
),
|
||||
links: payload.links.map(({ source_id, sink_id, ...rest }) => rest),
|
||||
};
|
||||
const comparedSavedAgent = {
|
||||
name: savedAgent?.name,
|
||||
@@ -947,7 +947,10 @@ export default function useAgentGraph(
|
||||
setNodesSyncedWithSavedAgent(false);
|
||||
|
||||
newSavedAgent = savedAgent
|
||||
? await api.updateGraph(savedAgent.id, payload)
|
||||
? await api.updateGraph(savedAgent.id, {
|
||||
...payload,
|
||||
id: savedAgent.id,
|
||||
})
|
||||
: await api.createGraph(payload);
|
||||
|
||||
console.debug("Response from the API:", newSavedAgent);
|
||||
@@ -996,7 +999,7 @@ export default function useAgentGraph(
|
||||
...edge,
|
||||
data: {
|
||||
...edge.data,
|
||||
edgeColor: edge.data?.edgeColor!,
|
||||
edgeColor: edge.data?.edgeColor ?? "grey",
|
||||
beadUp: 0,
|
||||
beadDown: 0,
|
||||
},
|
||||
|
||||
@@ -123,7 +123,7 @@ export default class BackendAPI {
|
||||
getUserCredit(): Promise<{ credits: number }> {
|
||||
try {
|
||||
return this._get("/credits");
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return Promise.resolve({ credits: 0 });
|
||||
}
|
||||
}
|
||||
@@ -223,7 +223,7 @@ export default class BackendAPI {
|
||||
version?: number,
|
||||
for_export?: boolean,
|
||||
): Promise<Graph> {
|
||||
let query: Record<string, any> = {};
|
||||
const query: Record<string, any> = {};
|
||||
if (version !== undefined) {
|
||||
query["version"] = version;
|
||||
}
|
||||
@@ -240,7 +240,7 @@ export default class BackendAPI {
|
||||
}
|
||||
|
||||
createGraph(graph: GraphCreatable): Promise<Graph> {
|
||||
let requestBody = { graph } as GraphCreateRequestBody;
|
||||
const requestBody = { graph } as GraphCreateRequestBody;
|
||||
|
||||
return this._request("POST", "/graphs", requestBody);
|
||||
}
|
||||
@@ -872,7 +872,7 @@ export default class BackendAPI {
|
||||
} else {
|
||||
errorDetail = errorData.detail || response.statusText;
|
||||
}
|
||||
} catch (e) {
|
||||
} catch {
|
||||
errorDetail = response.statusText;
|
||||
}
|
||||
|
||||
|
||||
@@ -630,6 +630,7 @@ export type StoreAgent = {
|
||||
description: string;
|
||||
runs: number;
|
||||
rating: number;
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type StoreAgentsResponse = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import { useEffect, useMemo, useState, useRef } from "react";
|
||||
import { createBrowserClient } from "@supabase/ssr";
|
||||
import { SignOut, User } from "@supabase/supabase-js";
|
||||
import { User } from "@supabase/supabase-js";
|
||||
import { useRouter } from "next/navigation";
|
||||
import {
|
||||
broadcastLogout,
|
||||
@@ -29,7 +29,7 @@ export function useSupabase() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
async function logOut(options?: SignOut) {
|
||||
async function logOut() {
|
||||
if (!supabase) return;
|
||||
|
||||
broadcastLogout();
|
||||
@@ -121,7 +121,7 @@ export function useSupabase() {
|
||||
|
||||
const {
|
||||
data: { subscription },
|
||||
} = supabase.auth.onAuthStateChange((event, session) => {
|
||||
} = supabase.auth.onAuthStateChange((_, session) => {
|
||||
const newUser = session?.user ?? null;
|
||||
|
||||
// Only update if user actually changed to prevent unnecessary re-renders
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { createServerClient } from "@supabase/ssr";
|
||||
import { NextResponse, type NextRequest } from "next/server";
|
||||
import {
|
||||
PROTECTED_PAGES,
|
||||
ADMIN_PAGES,
|
||||
isProtectedPage,
|
||||
isAdminPage,
|
||||
} from "./helpers";
|
||||
import { isAdminPage, isProtectedPage } from "./helpers";
|
||||
|
||||
export async function updateSession(request: NextRequest) {
|
||||
let supabaseResponse = NextResponse.next({
|
||||
@@ -31,7 +26,7 @@ export async function updateSession(request: NextRequest) {
|
||||
return request.cookies.getAll();
|
||||
},
|
||||
setAll(cookiesToSet) {
|
||||
cookiesToSet.forEach(({ name, value, options }) =>
|
||||
cookiesToSet.forEach(({ name, value }) =>
|
||||
request.cookies.set(name, value),
|
||||
);
|
||||
supabaseResponse = NextResponse.next({
|
||||
@@ -51,7 +46,6 @@ export async function updateSession(request: NextRequest) {
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
error,
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
const userRole = user?.role;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import type { UnsafeUnwrappedCookies } from "next/headers";
|
||||
import { createServerClient } from "@supabase/ssr";
|
||||
import { createServerClient, type CookieOptions } from "@supabase/ssr";
|
||||
|
||||
type Cookies = { name: string; value: string; options?: CookieOptions }[];
|
||||
|
||||
export async function getServerSupabase() {
|
||||
// Need require here, so Next.js doesn't complain about importing this on client side
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const { cookies } = require("next/headers");
|
||||
const cookieStore = await cookies();
|
||||
|
||||
@@ -15,7 +17,7 @@ export async function getServerSupabase() {
|
||||
getAll() {
|
||||
return cookieStore.getAll();
|
||||
},
|
||||
setAll(cookiesToSet) {
|
||||
setAll(cookiesToSet: Cookies) {
|
||||
try {
|
||||
cookiesToSet.forEach(({ name, value, options }) =>
|
||||
cookieStore.set(name, value, options),
|
||||
|
||||
@@ -10,7 +10,6 @@ export async function getServerUser() {
|
||||
try {
|
||||
const {
|
||||
data: { user },
|
||||
error: _,
|
||||
} = await supabase.auth.getUser();
|
||||
// if (error) {
|
||||
// // FIX: Suppressing error for now. Need to stop the nav bar calling this all the time
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { Category, Graph } from "@/lib/autogpt-server-api/types";
|
||||
import { Category } from "@/lib/autogpt-server-api/types";
|
||||
import { NodeDimension } from "@/components/Flow";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import type { Meta } from "@storybook/react";
|
||||
import { Text } from "@/components/_new/Text/Text";
|
||||
import { StoryCode } from "@/stories/helpers/StoryCode";
|
||||
import { SquareArrowOutUpRight } from "lucide-react";
|
||||
@@ -271,5 +271,3 @@ export function AllVariants() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import type { Meta } from "@storybook/react";
|
||||
import { Text } from "@/components/_new/Text/Text";
|
||||
import { StoryCode } from "@/stories/helpers/StoryCode";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import type { Meta } from "@storybook/react";
|
||||
import { Text } from "@/components/_new/Text/Text";
|
||||
import { StoryCode } from "@/stories/helpers/StoryCode";
|
||||
import { SquareArrowOutUpRight } from "lucide-react";
|
||||
@@ -248,5 +248,3 @@ export function AllVariants() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
@@ -1,62 +1,45 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { Text } from "@/components/_new/Text/Text";
|
||||
import { StoryCode } from "@/stories/helpers/StoryCode";
|
||||
import { SquareArrowOutUpRight } from "lucide-react";
|
||||
import {
|
||||
User,
|
||||
UserPlus,
|
||||
Key,
|
||||
FlowArrow,
|
||||
Play,
|
||||
Square,
|
||||
Alien,
|
||||
ArrowClockwise,
|
||||
FloppyDisk,
|
||||
ArrowCounterClockwise,
|
||||
ArrowClockwise as Redo,
|
||||
Cube,
|
||||
Warning,
|
||||
UserCircle,
|
||||
Package,
|
||||
Megaphone,
|
||||
List,
|
||||
Coin,
|
||||
PencilSimple,
|
||||
SignOut,
|
||||
Gear,
|
||||
SquaresFour,
|
||||
CloudArrowUp,
|
||||
MediumLogo,
|
||||
YoutubeLogo,
|
||||
TiktokLogo,
|
||||
Globe,
|
||||
Hammer,
|
||||
Books,
|
||||
GithubLogo,
|
||||
LinkedinLogo,
|
||||
FacebookLogo,
|
||||
XLogo,
|
||||
InstagramLogo,
|
||||
ArrowLeft,
|
||||
ArrowRight,
|
||||
Heart,
|
||||
Star,
|
||||
Bell,
|
||||
MagnifyingGlass,
|
||||
Plus,
|
||||
X,
|
||||
Books,
|
||||
Check,
|
||||
Info,
|
||||
Download,
|
||||
Upload,
|
||||
Calendar,
|
||||
Clock,
|
||||
Eye,
|
||||
EyeSlash,
|
||||
CloudArrowUp,
|
||||
Copy,
|
||||
Cube,
|
||||
Download,
|
||||
FacebookLogo,
|
||||
FloppyDisk,
|
||||
FlowArrow,
|
||||
Gear,
|
||||
GithubLogo,
|
||||
Info,
|
||||
InstagramLogo,
|
||||
Key,
|
||||
LinkedinLogo,
|
||||
List,
|
||||
Package,
|
||||
PencilSimple,
|
||||
Play,
|
||||
ArrowClockwise as Redo,
|
||||
SignOut,
|
||||
SquaresFour,
|
||||
Trash,
|
||||
DotsThreeVertical,
|
||||
Alien,
|
||||
User,
|
||||
UserCircle,
|
||||
UserPlus,
|
||||
Warning,
|
||||
X,
|
||||
XLogo,
|
||||
YoutubeLogo,
|
||||
} from "@phosphor-icons/react";
|
||||
import type { Meta } from "@storybook/react";
|
||||
import { SquareArrowOutUpRight } from "lucide-react";
|
||||
|
||||
const meta: Meta = {
|
||||
title: "Design System/ Tokens /Icons",
|
||||
@@ -458,5 +441,3 @@ import { User, Heart, Star, Bell } from "@phosphor-icons/react";
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
@@ -13,7 +13,7 @@ test.describe("Build", () => { //(1)!
|
||||
|
||||
// Reason Ignore: admonishment is in the wrong place visually with correct prettier rules
|
||||
// prettier-ignore
|
||||
test.beforeEach(async ({ page, loginPage, testUser }, testInfo) => { //(3)! ts-ignore
|
||||
test.beforeEach(async ({ page, loginPage, testUser }) => { //(3)! ts-ignore
|
||||
buildPage = new BuildPage(page);
|
||||
|
||||
// Start each test with login using worker auth
|
||||
|
||||
@@ -1,42 +1,6 @@
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
||||
|
||||
export type TestUser = {
|
||||
email: string;
|
||||
password: string;
|
||||
id?: string;
|
||||
};
|
||||
|
||||
let supabase: SupabaseClient;
|
||||
|
||||
function getSupabaseAdmin() {
|
||||
if (!supabase) {
|
||||
supabase = createClient(
|
||||
process.env.SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE_KEY!,
|
||||
{
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
return supabase;
|
||||
}
|
||||
|
||||
async function deleteTestUser(userId: string) {
|
||||
const supabase = getSupabaseAdmin();
|
||||
|
||||
try {
|
||||
const { error } = await supabase.auth.admin.deleteUser(userId);
|
||||
|
||||
if (error) {
|
||||
console.warn(`Warning: Failed to delete test user: ${error.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Warning: Error during user cleanup: ${(error as Error).message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect, TestInfo } from "@playwright/test";
|
||||
import { TestInfo } from "@playwright/test";
|
||||
import { test } from "./fixtures";
|
||||
import { BuildPage } from "./pages/build.page";
|
||||
import { MonitorPage } from "./pages/monitor.page";
|
||||
@@ -48,7 +48,7 @@ test.describe("Monitor", () => {
|
||||
});
|
||||
});
|
||||
|
||||
test("user can view agents", async ({ page }) => {
|
||||
test("user can view agents", async () => {
|
||||
const agents = await monitorPage.listAgents();
|
||||
// there should be at least one agent
|
||||
await test.expect(agents.length).toBeGreaterThan(0);
|
||||
@@ -117,7 +117,7 @@ test.describe("Monitor", () => {
|
||||
await test.expect(importedAgent).toBeDefined();
|
||||
});
|
||||
|
||||
test("user can view runs", async ({ page }) => {
|
||||
test("user can view runs", async () => {
|
||||
const runs = await monitorPage.listRuns();
|
||||
console.log(runs);
|
||||
// there should be at least one run
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ElementHandle, Locator, Page } from "@playwright/test";
|
||||
import { Locator, Page } from "@playwright/test";
|
||||
import { BasePage } from "./base.page";
|
||||
|
||||
export interface Block {
|
||||
@@ -136,7 +136,7 @@ export class BuildPage extends BasePage {
|
||||
}
|
||||
}
|
||||
|
||||
async getBlockOutputs(blockId: string): Promise<string[]> {
|
||||
async getBlockOutputs(): Promise<string[]> {
|
||||
throw new Error("Not implemented");
|
||||
// try {
|
||||
// const node = await this.page
|
||||
@@ -151,7 +151,7 @@ export class BuildPage extends BasePage {
|
||||
}
|
||||
|
||||
async _buildBlockSelector(blockId: string, dataId?: string): Promise<string> {
|
||||
let selector = dataId
|
||||
const selector = dataId
|
||||
? `[data-id="${dataId}"] [data-blockid="${blockId}"]`
|
||||
: `[data-blockid="${blockId}"]`;
|
||||
return selector;
|
||||
@@ -283,7 +283,7 @@ export class BuildPage extends BasePage {
|
||||
try {
|
||||
await this.page.waitForLoadState("domcontentloaded", { timeout: 10_000 });
|
||||
return true;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -432,8 +432,8 @@ export class BuildPage extends BasePage {
|
||||
}
|
||||
|
||||
// Parse current coordinates
|
||||
let currentX = parseFloat(matches[1]);
|
||||
let currentY = parseFloat(matches[2]);
|
||||
const currentX = parseFloat(matches[1]);
|
||||
const currentY = parseFloat(matches[2]);
|
||||
|
||||
// Calculate new position
|
||||
let newX = currentX;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ElementHandle, Locator, Page } from "@playwright/test";
|
||||
import { Page } from "@playwright/test";
|
||||
import { BasePage } from "./base.page";
|
||||
import path from "path";
|
||||
|
||||
@@ -18,10 +18,6 @@ interface Run {
|
||||
status: string;
|
||||
}
|
||||
|
||||
interface AgentRun extends Agent {
|
||||
runs: Run[];
|
||||
}
|
||||
|
||||
interface Schedule {
|
||||
id: string;
|
||||
graphName: string;
|
||||
@@ -72,7 +68,7 @@ export class MonitorPage extends BasePage {
|
||||
]);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ test.describe("Profile", () => {
|
||||
await test.expect(page).toHaveURL("/marketplace");
|
||||
});
|
||||
|
||||
test("user can view their profile information", async ({
|
||||
page,
|
||||
testUser,
|
||||
}) => {
|
||||
test("user can view their profile information", async ({ page }) => {
|
||||
await profilePage.navbar.clickProfileLink();
|
||||
// workaround for #8788
|
||||
// sleep for 10 seconds to allow page to load due to bug in our system
|
||||
@@ -39,7 +36,7 @@ test.describe("Profile", () => {
|
||||
await test.expect(profilePage.isLoaded()).resolves.toBeTruthy();
|
||||
});
|
||||
|
||||
test("profile displays user Credential providers", async ({ page }) => {
|
||||
test("profile displays user Credential providers", async () => {
|
||||
await profilePage.navbar.clickProfileLink();
|
||||
|
||||
// await test
|
||||
|
||||
@@ -99,6 +99,7 @@ test.describe("Nested Property Setter Tests", () => {
|
||||
}).toThrow("Invalid property name: __proto__");
|
||||
|
||||
// Verify no pollution occurred
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
expect({}.polluted).toBeUndefined();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user