Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion frontend/src/api/system.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { API_QUERY_KEYS, VALUECELL_BACKEND_URL } from "@/constants/api";
import i18n from "@/i18n";
import { type ApiResponse, apiClient } from "@/lib/api-client";
import { useLanguage } from "@/store/settings-store";
import { useSystemStore } from "@/store/system-store";
Expand Down Expand Up @@ -111,7 +112,7 @@ export const usePublishStrategy = () => {
);
},
onSuccess: () => {
toast.success("Strategy published successfully");
toast.success(i18n.t("strategy.toast.published"));
queryClient.invalidateQueries({
queryKey: API_QUERY_KEYS.SYSTEM.strategyList([]),
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useStore } from "@tanstack/react-form";
import { AlertCircleIcon } from "lucide-react";
import type { FC, RefObject } from "react";
import { memo, useImperativeHandle, useState } from "react";
import { memo, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useGetModelProviderDetail } from "@/api/setting";
import {
Expand Down Expand Up @@ -29,9 +29,9 @@ import { TradingStrategyForm } from "@/components/valuecell/form/trading-strateg
import { StepIndicator } from "@/components/valuecell/step-indicator";
import { TRADING_SYMBOLS } from "@/constants/agent";
import {
aiModelSchema,
exchangeSchema,
tradingStrategySchema,
createAiModelSchema,
createExchangeSchema,
createTradingStrategySchema,
} from "@/constants/schema";
import { useAppForm } from "@/hooks/use-form";
import { tracker } from "@/lib/tracker";
Expand All @@ -50,6 +50,12 @@ const CreateStrategyModal: FC<CreateStrategyModalProps> = ({
children,
}) => {
const { t } = useTranslation();
const aiModelSchema = useMemo(() => createAiModelSchema(t), [t]);
const exchangeSchema = useMemo(() => createExchangeSchema(t), [t]);
const tradingStrategySchema = useMemo(
() => createTradingStrategySchema(t),
[t],
);
const [open, setOpen] = useState(false);
const [currentStep, setCurrentStep] = useState(1);
const [error, setError] = useState<string | null>(null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
useRef,
useState,
} from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
Expand Down Expand Up @@ -38,6 +39,7 @@ export interface SharePortfolioCardRef {
const SharePortfolioModal: FC<{
ref?: RefObject<SharePortfolioCardRef | null>;
}> = ({ ref }) => {
const { t } = useTranslation();
const cardRef = useRef<HTMLDivElement>(null);
const [isDownloading, setIsDownloading] = useState(false);

Expand Down Expand Up @@ -84,18 +86,21 @@ const SharePortfolioModal: FC<{
await writeFile(path, new Uint8Array(arrayBuffer));

setOpen(false);
toast.success("Image downloaded successfully", {
toast.success(t("sharePortfolio.toast.downloaded"), {
action: {
label: "open file",
label: t("sharePortfolio.toast.openFile"),
onClick: async () => {
return await openPath(path);
},
},
});
} catch (err) {
toast.error(`Failed to download image: ${JSON.stringify(err)}`, {
duration: 6 * 1000,
});
toast.error(
t("sharePortfolio.toast.downloadFailed", {
error: JSON.stringify(err),
}),
{ duration: 6 * 1000 },
);
} finally {
setIsDownloading(false);
}
Expand All @@ -116,7 +121,9 @@ const SharePortfolioModal: FC<{
className="h-[600px] w-[434px] overflow-hidden border-none bg-transparent p-0 shadow-none"
showCloseButton={false}
>
<DialogTitle className="sr-only">Share Portfolio</DialogTitle>
<DialogTitle className="sr-only">
{t("sharePortfolio.title")}
</DialogTitle>

{/* Card to be captured */}
<div
Expand Down Expand Up @@ -166,10 +173,10 @@ const SharePortfolioModal: FC<{
{formatChange(data.total_pnl, "", 2)}
</span>

<p>Model</p>
<p>{t("sharePortfolio.fields.model")}</p>
<span>{data.llm_model_id}</span>

<p>Exchange</p>
<p>{t("sharePortfolio.fields.exchange")}</p>
<span className="ml-auto flex items-center gap-1">
<PngIcon
src={
Expand All @@ -182,7 +189,7 @@ const SharePortfolioModal: FC<{
{data.exchange_id}
</span>

<p>Strategy</p>
<p>{t("sharePortfolio.fields.strategy")}</p>
<span>{data.strategy_type}</span>
</div>

Expand Down Expand Up @@ -219,7 +226,7 @@ const SharePortfolioModal: FC<{
className="h-12 flex-1 rounded-xl border-border bg-card font-medium text-base hover:bg-muted"
onClick={() => setOpen(false)}
>
Cancel
{t("strategy.action.cancel")}
</Button>

<Button
Expand All @@ -232,7 +239,7 @@ const SharePortfolioModal: FC<{
) : (
<Download className="mr-2 size-5" />
)}
Download
{t("sharePortfolio.action.download")}
</Button>
</div>
</DialogContent>
Expand Down
16 changes: 12 additions & 4 deletions frontend/src/app/setting/general.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,18 @@ export default function GeneralPage() {
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="en">English (United States)</SelectItem>
<SelectItem value="zh_CN">简体中文</SelectItem>
<SelectItem value="zh_TW">繁體中文</SelectItem>
<SelectItem value="ja">日本語</SelectItem>
<SelectItem value="en">
{t("general.language.options.en")}
</SelectItem>
<SelectItem value="zh_CN">
{t("general.language.options.zh_CN")}
</SelectItem>
<SelectItem value="zh_TW">
{t("general.language.options.zh_TW")}
</SelectItem>
<SelectItem value="ja">
{t("general.language.options.ja")}
</SelectItem>
</SelectContent>
</Select>
</Field>
Expand Down
14 changes: 8 additions & 6 deletions frontend/src/components/valuecell/app/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
type ReactNode,
useMemo,
} from "react";
import { useTranslation } from "react-i18next";
import { NavLink, useLocation } from "react-router";
import { useGetAgentList } from "@/api/agent";
import {
Expand Down Expand Up @@ -126,6 +127,7 @@ const SidebarMenuItem: FC<SidebarItemProps> = ({
};

const AppSidebar: FC = () => {
const { t } = useTranslation();
const pathArray = useLocation().pathname.split("/");

const prefix = useMemo(() => {
Expand All @@ -144,38 +146,38 @@ const AppSidebar: FC = () => {
{
id: "home",
icon: Logo,
label: "Home",
label: t("nav.home"),
to: "/home",
},
{
id: "strategy",
icon: StrategyAgent,
label: "Strategy",
label: t("nav.strategy"),
to: "/agent/StrategyAgent",
},
{
id: "ranking",
icon: Ranking,
label: "Ranking",
label: t("nav.ranking"),
to: "/ranking",
},
{
id: "market",
icon: Market,
label: "Market",
label: t("nav.market"),
to: "/market",
},
],
config: [
{
id: "setting",
icon: Setting,
label: "Setting",
label: t("nav.setting"),
to: "/setting",
},
],
};
}, []);
}, [t]);

const { data: agentList } = useGetAgentList({ enabled_only: "true" });
const agentItems = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AnimatePresence, motion } from "framer-motion";
import type React from "react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useBackendHealth } from "@/api/system";
import ValuecellLogo from "@/assets/png/logo/valuecell-logo.webp";
import { Progress } from "@/components/ui/progress";
Expand All @@ -10,6 +11,7 @@ export function BackendHealthCheck({
}: {
children: React.ReactNode;
}) {
const { t } = useTranslation();
const { isError, isSuccess } = useBackendHealth();
const [showError, setShowError] = useState(false);
const [progress, setProgress] = useState(0);
Expand Down Expand Up @@ -92,7 +94,7 @@ export function BackendHealthCheck({
className="space-y-4"
>
<p className="text-lg text-muted-foreground leading-relaxed">
Setting up environment...
{t("common.settingUpEnvironment")}
</p>
</motion.div>

Expand All @@ -106,7 +108,7 @@ export function BackendHealthCheck({
<div className="max-w-lg space-y-2">
<Progress value={progress} className="h-2 w-full bg-muted/50" />
<div className="flex justify-between font-medium text-muted-foreground text-xs uppercase tracking-wider">
<span>Loading</span>
<span>{t("common.loading")}</span>
<span>{Math.round(progress)}%</span>
</div>
</div>
Expand Down
43 changes: 29 additions & 14 deletions frontend/src/components/valuecell/modal/copy-strategy-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useStore } from "@tanstack/react-form";
import { AlertCircleIcon } from "lucide-react";
import type { FC, RefObject } from "react";
import { memo, useImperativeHandle, useState } from "react";
import { memo, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useGetModelProviderDetail } from "@/api/setting";
import {
useCreateStrategy,
Expand All @@ -27,9 +28,9 @@ import {
import { StepIndicator } from "@/components/valuecell/step-indicator";
import { TRADING_SYMBOLS } from "@/constants/agent";
import {
aiModelSchema,
copyTradingStrategySchema,
exchangeSchema,
createAiModelSchema,
createCopyTradingStrategySchema,
createExchangeSchema,
} from "@/constants/schema";
import { useAppForm } from "@/hooks/use-form";
import { tracker } from "@/lib/tracker";
Expand All @@ -45,22 +46,32 @@ interface CopyStrategyModalProps {
callback?: () => void;
}

const STEPS = [
{ step: 1, title: "AI Models" },
{ step: 2, title: "Exchanges" },
{ step: 3, title: "Trading strategy" },
];

const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
ref,
children,
callback,
}) => {
const { t } = useTranslation();
const aiModelSchema = useMemo(() => createAiModelSchema(t), [t]);
const exchangeSchema = useMemo(() => createExchangeSchema(t), [t]);
const copyTradingStrategySchema = useMemo(
() => createCopyTradingStrategySchema(t),
[t],
);
const [open, setOpen] = useState(false);
const [currentStep, setCurrentStep] = useState(1);
const [defaultValues, setDefaultValues] = useState<CopyStrategy>();
const [error, setError] = useState<string | null>(null);

const STEPS = useMemo(
() => [
{ step: 1, title: t("strategy.create.steps.aiModels") },
{ step: 2, title: t("strategy.create.steps.exchanges") },
{ step: 3, title: t("strategy.create.steps.tradingStrategy") },
],
[t],
);

const { data: strategies = [] } = useGetStrategyList();
const { mutateAsync: createStrategy, isPending: isCreatingStrategy } =
useCreateStrategy();
Expand Down Expand Up @@ -201,7 +212,7 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
<DialogTitle className="flex flex-col gap-4 px-1">
<div className="flex items-center justify-between">
<h2 className="font-semibold text-lg">
Duplicate trading strategy
{t("strategy.copy.title")}
</h2>
<CloseButton onClick={resetAll} />
</div>
Expand Down Expand Up @@ -230,7 +241,7 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
{error && (
<Alert variant="destructive">
<AlertCircleIcon />
<AlertTitle>Error Duplicating Strategy</AlertTitle>
<AlertTitle>{t("strategy.copy.error")}</AlertTitle>
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
Expand All @@ -241,7 +252,9 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
onClick={currentStep === 1 ? resetAll : handleBack}
className="py-4 font-semibold text-base"
>
{currentStep === 1 ? "Cancel" : "Back"}
{currentStep === 1
? t("strategy.action.cancel")
: t("strategy.action.back")}
</Button>
<Button
type="button"
Expand All @@ -261,7 +274,9 @@ const CopyStrategyModal: FC<CopyStrategyModalProps> = ({
className="relative py-4 font-semibold text-base"
>
{isCreatingStrategy && <Spinner className="absolute left-4" />}
{currentStep === 3 ? "Confirm" : "Next"}
{currentStep === 3
? t("strategy.action.confirm")
: t("strategy.action.next")}
</Button>
</div>
</DialogFooter>
Expand Down
Loading