mirror of
https://github.com/ReaJason/MemShellParty.git
synced 2026-09-21 22:50:42 +08:00
refactor: use react router
This commit is contained in:
@@ -1,11 +1,9 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.boot.entity.Config;
|
|
||||||
import com.reajason.javaweb.memshell.Packers;
|
import com.reajason.javaweb.memshell.Packers;
|
||||||
import com.reajason.javaweb.memshell.Server;
|
import com.reajason.javaweb.memshell.Server;
|
||||||
import com.reajason.javaweb.memshell.ShellTool;
|
import com.reajason.javaweb.memshell.ShellTool;
|
||||||
import com.reajason.javaweb.memshell.server.AbstractShell;
|
import com.reajason.javaweb.memshell.server.AbstractShell;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@@ -20,8 +18,28 @@ import java.util.*;
|
|||||||
@RequestMapping("/config")
|
@RequestMapping("/config")
|
||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class ConfigController {
|
public class ConfigController {
|
||||||
|
|
||||||
|
@RequestMapping("/servers")
|
||||||
|
public Map<String, List<String>> getServers() {
|
||||||
|
Map<String, List<String>> servers = new LinkedHashMap<>();
|
||||||
|
for (Server server : Server.values()) {
|
||||||
|
if (server.getShell() != null) {
|
||||||
|
Set<String> supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes();
|
||||||
|
servers.put(server.name(), supportedShellTypes.stream().toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return servers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/packers")
|
||||||
|
public List<String> getPackers() {
|
||||||
|
return Arrays.stream(Packers.values())
|
||||||
|
.filter(packers -> packers.getParentPacker() == null)
|
||||||
|
.map(Packers::name).toList();
|
||||||
|
}
|
||||||
|
|
||||||
@RequestMapping
|
@RequestMapping
|
||||||
public ResponseEntity<?> config() {
|
public Map<String, Map<?, ?>> config() {
|
||||||
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
Map<String, Map<?, ?>> coreMap = new HashMap<>(16);
|
||||||
for (Server value : Server.values()) {
|
for (Server value : Server.values()) {
|
||||||
AbstractShell shell = value.getShell();
|
AbstractShell shell = value.getShell();
|
||||||
@@ -38,21 +56,6 @@ public class ConfigController {
|
|||||||
}
|
}
|
||||||
coreMap.put(value.name(), map);
|
coreMap.put(value.name(), map);
|
||||||
}
|
}
|
||||||
Config config = new Config();
|
return coreMap;
|
||||||
Map<String, List<String>> servers = new LinkedHashMap<>();
|
|
||||||
for (Server server : Server.values()) {
|
|
||||||
if (server.getShell() != null) {
|
|
||||||
Set<String> supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes();
|
|
||||||
servers.put(server.name(), supportedShellTypes.stream().toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
config.setServers(servers);
|
|
||||||
config.setCore(coreMap);
|
|
||||||
config.setPackers(
|
|
||||||
Arrays.stream(Packers.values())
|
|
||||||
.filter(packers -> packers.getParentPacker() == null)
|
|
||||||
.map(Packers::name).toList()
|
|
||||||
);
|
|
||||||
return ResponseEntity.ok(config);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package com.reajason.javaweb.boot.controller;
|
package com.reajason.javaweb.boot.controller;
|
||||||
|
|
||||||
import com.reajason.javaweb.memshell.MemShellGenerator;
|
|
||||||
import com.reajason.javaweb.boot.dto.GenerateRequest;
|
import com.reajason.javaweb.boot.dto.GenerateRequest;
|
||||||
import com.reajason.javaweb.boot.dto.GenerateResponse;
|
import com.reajason.javaweb.boot.dto.GenerateResponse;
|
||||||
|
import com.reajason.javaweb.memshell.MemShellGenerator;
|
||||||
import com.reajason.javaweb.memshell.config.GenerateResult;
|
import com.reajason.javaweb.memshell.config.GenerateResult;
|
||||||
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
import com.reajason.javaweb.memshell.config.InjectorConfig;
|
||||||
import com.reajason.javaweb.memshell.config.ShellConfig;
|
import com.reajason.javaweb.memshell.config.ShellConfig;
|
||||||
@@ -10,7 +10,6 @@ import com.reajason.javaweb.memshell.config.ShellToolConfig;
|
|||||||
import com.reajason.javaweb.memshell.packer.AggregatePacker;
|
import com.reajason.javaweb.memshell.packer.AggregatePacker;
|
||||||
import com.reajason.javaweb.memshell.packer.Packer;
|
import com.reajason.javaweb.memshell.packer.Packer;
|
||||||
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
import com.reajason.javaweb.memshell.packer.jar.JarPacker;
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
@@ -24,18 +23,18 @@ import java.util.Base64;
|
|||||||
@CrossOrigin("*")
|
@CrossOrigin("*")
|
||||||
public class GeneratorController {
|
public class GeneratorController {
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity<?> generate(@RequestBody GenerateRequest request) {
|
public GenerateResponse generate(@RequestBody GenerateRequest request) {
|
||||||
ShellConfig shellConfig = request.getShellConfig();
|
ShellConfig shellConfig = request.getShellConfig();
|
||||||
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
ShellToolConfig shellToolConfig = request.parseShellToolConfig();
|
||||||
InjectorConfig injectorConfig = request.getInjectorConfig();
|
InjectorConfig injectorConfig = request.getInjectorConfig();
|
||||||
GenerateResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
GenerateResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig);
|
||||||
Packer packer = request.getPacker().getInstance();
|
Packer packer = request.getPacker().getInstance();
|
||||||
if (packer instanceof JarPacker) {
|
if (packer instanceof JarPacker) {
|
||||||
return ResponseEntity.ok(new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult))));
|
return new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult)));
|
||||||
} else if (packer instanceof AggregatePacker) {
|
} else if (packer instanceof AggregatePacker) {
|
||||||
return ResponseEntity.ok(new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult)));
|
return new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult));
|
||||||
} else {
|
} else {
|
||||||
return ResponseEntity.ok(new GenerateResponse(generateResult, packer.pack(generateResult)));
|
return new GenerateResponse(generateResult, packer.pack(generateResult));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
+9
-12
@@ -15,17 +15,16 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "1.9.4",
|
||||||
"@tanstack/router-plugin": "^1.114.32",
|
"@types/node": "^22.14.0",
|
||||||
"@types/node": "^22.13.17",
|
|
||||||
"@types/react": "^19.1.0",
|
"@types/react": "^19.1.0",
|
||||||
"@types/react-copy-to-clipboard": "^5.0.7",
|
"@types/react-copy-to-clipboard": "^5.0.7",
|
||||||
"@types/react-dom": "^19.1.1",
|
"@types/react-dom": "^19.1.1",
|
||||||
"@types/react-syntax-highlighter": "^15.5.13",
|
"@types/react-syntax-highlighter": "^15.5.13",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^4.3.4",
|
||||||
"rimraf": "^6.0.1",
|
"rimraf": "^6.0.1",
|
||||||
"tailwindcss": "^4.1.1",
|
"tailwindcss": "^4.1.3",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^6.2.4",
|
"vite": "^6.2.5",
|
||||||
"vite-bundle-visualizer": "^1.2.1"
|
"vite-bundle-visualizer": "^1.2.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -56,19 +55,15 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.2",
|
"@radix-ui/react-toggle": "^1.1.2",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
"@tailwindcss/vite": "^4.1.1",
|
"@tailwindcss/vite": "^4.1.3",
|
||||||
"@tanstack/react-query": "^5.71.3",
|
|
||||||
"@tanstack/react-router": "^1.114.32",
|
|
||||||
"@tanstack/router-devtools": "^1.114.32",
|
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"embla-carousel-react": "^8.5.2",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"i18next": "^24.2.3",
|
"i18next": "^24.2.3",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^0.487.0",
|
"lucide-react": "^0.487.0",
|
||||||
"next-themes": "^0.4.6",
|
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-copy-to-clipboard": "^5.1.0",
|
"react-copy-to-clipboard": "^5.1.0",
|
||||||
"react-day-picker": "9.6.4",
|
"react-day-picker": "9.6.4",
|
||||||
@@ -76,8 +71,10 @@
|
|||||||
"react-hook-form": "^7.55.0",
|
"react-hook-form": "^7.55.0",
|
||||||
"react-i18next": "^15.4.1",
|
"react-i18next": "^15.4.1",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
|
"react-router": "^7.5.0",
|
||||||
|
"react-router-dom": "^7.5.0",
|
||||||
"react-syntax-highlighter": "^15.6.1",
|
"react-syntax-highlighter": "^15.6.1",
|
||||||
"recharts": "^2.15.1",
|
"recharts": "^2.15.2",
|
||||||
"sonner": "^2.0.3",
|
"sonner": "^2.0.3",
|
||||||
"tailwind-merge": "^3.1.0",
|
"tailwind-merge": "^3.1.0",
|
||||||
"tailwind-scrollbar": "^4.0.2",
|
"tailwind-scrollbar": "^4.0.2",
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
import { LanguageSwitcher } from "@/components/language-switcher";
|
import { LanguageSwitcher } from "@/components/language-switcher";
|
||||||
import { ModeToggle } from "@/components/mode-toggle.tsx";
|
import { ModeToggle } from "@/components/mode-toggle.tsx";
|
||||||
import { ThemeProvider } from "@/components/theme-provider.tsx";
|
import { ThemeProvider } from "@/components/theme-provider.tsx";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
import VersionBadge from "@/components/version-badge";
|
import VersionBadge from "@/components/version-badge";
|
||||||
import { GitHubIcon } from "@/icon";
|
import { GitHubIcon } from "@/icon";
|
||||||
import { Outlet, createRootRoute } from "@tanstack/react-router";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { Outlet } from "react-router-dom";
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
|
||||||
component: RootComponent,
|
|
||||||
});
|
|
||||||
|
|
||||||
function RootComponent() {
|
export default function RootLayout() {
|
||||||
return (
|
return (
|
||||||
<ThemeProvider defaultTheme="system" storageKey="vite-ui-theme">
|
<ThemeProvider defaultTheme="system" storageKey="vite-ui-theme">
|
||||||
<Toaster />
|
<Toaster />
|
||||||
@@ -42,4 +39,4 @@ function RootComponent() {
|
|||||||
</div>
|
</div>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
+5
-19
@@ -1,37 +1,23 @@
|
|||||||
import { RouterProvider, createRouter } from "@tanstack/react-router";
|
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import { routeTree } from "./routeTree.gen";
|
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import { TailwindIndicator } from "@/components/tailwind-indicator.tsx";
|
import { TailwindIndicator } from "@/components/tailwind-indicator.tsx";
|
||||||
import { env } from "@/config.ts";
|
import { env } from "@/config.ts";
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
||||||
import { I18nextProvider } from "react-i18next";
|
import { I18nextProvider } from "react-i18next";
|
||||||
import i18n from "./i18n/i18n";
|
import i18n from "./i18n/i18n";
|
||||||
|
import { RouterProvider } from "react-router-dom";
|
||||||
const queryClient = new QueryClient();
|
import { router } from "./router";
|
||||||
|
import { QueryProvider } from "./providers/query-client-provider";
|
||||||
const router = createRouter({
|
|
||||||
routeTree,
|
|
||||||
basepath: env.BASE_PATH,
|
|
||||||
defaultPreload: "intent",
|
|
||||||
});
|
|
||||||
|
|
||||||
declare module "@tanstack/react-router" {
|
|
||||||
interface Register {
|
|
||||||
router: typeof router;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const rootElement = document.getElementById("app") as HTMLElement;
|
const rootElement = document.getElementById("app") as HTMLElement;
|
||||||
|
|
||||||
if (!rootElement.innerHTML) {
|
if (!rootElement.innerHTML) {
|
||||||
const root = ReactDOM.createRoot(rootElement);
|
const root = ReactDOM.createRoot(rootElement);
|
||||||
root.render(
|
root.render(
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryProvider>
|
||||||
<I18nextProvider i18n={i18n}>
|
<I18nextProvider i18n={i18n}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
{env.MODE !== "production" && <TailwindIndicator />}
|
{env.MODE !== "production" && <TailwindIndicator />}
|
||||||
</I18nextProvider>
|
</I18nextProvider>
|
||||||
</QueryClientProvider>,
|
</QueryProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,41 +10,56 @@ import {
|
|||||||
ConfigResponseType,
|
ConfigResponseType,
|
||||||
GenerateResponse,
|
GenerateResponse,
|
||||||
GenerateResult,
|
GenerateResult,
|
||||||
|
MainConfig,
|
||||||
|
PackerConfig,
|
||||||
|
ServerConfig,
|
||||||
ShellToolType,
|
ShellToolType,
|
||||||
} from "@/types/shell.ts";
|
} from "@/types/shell.ts";
|
||||||
import { transformToPostData } from "@/utils/transformer.ts";
|
import { customValidation, transformToPostData } from "@/utils/transformer.ts";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
|
||||||
import { createFileRoute } from "@tanstack/react-router";
|
|
||||||
import { LoaderCircle, WandSparklesIcon } from "lucide-react";
|
import { LoaderCircle, WandSparklesIcon } from "lucide-react";
|
||||||
import { useState, useTransition } from "react";
|
import { useState, useTransition } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
export const Route = createFileRoute("/")({
|
export default function IndexPage() {
|
||||||
component: IndexComponent,
|
const { data: serverConfig } = useQuery<ServerConfig>({
|
||||||
});
|
queryKey: ["serverConfig"],
|
||||||
|
queryFn: async () => {
|
||||||
|
const response = await fetch(`${env.API_URL}/config/servers`);
|
||||||
|
return await response.json();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
function IndexComponent() {
|
const { data: mainConfig } = useQuery<MainConfig>({
|
||||||
const { data } = useQuery<ConfigResponseType>({
|
queryKey: ["mainConfig"],
|
||||||
queryKey: ["config"],
|
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const response = await fetch(`${env.API_URL}/config`);
|
const response = await fetch(`${env.API_URL}/config`);
|
||||||
return await response.json();
|
return await response.json();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data: packerConfig } = useQuery<PackerConfig>({
|
||||||
|
queryKey: ["packerConfig"],
|
||||||
|
queryFn: async () => {
|
||||||
|
const response = await fetch(`${env.API_URL}/config/packers`);
|
||||||
|
return await response.json();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const form = useForm<FormSchema>({
|
const form = useForm<FormSchema>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
server: "",
|
server: "Tomcat",
|
||||||
targetJdkVersion: "50",
|
targetJdkVersion: "50",
|
||||||
debug: false,
|
debug: false,
|
||||||
bypassJavaModule: false,
|
bypassJavaModule: false,
|
||||||
shellClassName: "",
|
shellClassName: "",
|
||||||
shellTool: "Godzilla",
|
shellTool: "Godzilla",
|
||||||
shellType: "",
|
shellType: "Listener",
|
||||||
urlPattern: "/*",
|
urlPattern: "/*",
|
||||||
godzillaPass: "pass",
|
godzillaPass: "pass",
|
||||||
godzillaKey: "key",
|
godzillaKey: "key",
|
||||||
@@ -64,40 +79,11 @@ function IndexComponent() {
|
|||||||
const [packMethod, setPackMethod] = useState<string>("");
|
const [packMethod, setPackMethod] = useState<string>("");
|
||||||
const [isActionPending, startTransition] = useTransition();
|
const [isActionPending, startTransition] = useTransition();
|
||||||
|
|
||||||
function customValidation(values: FormSchema) {
|
const onSubmit = async (data: FormSchema) => {
|
||||||
if (values.shellType.endsWith("Servlet") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
|
||||||
toast.warning(t("tips.servletUrlPattern"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.shellType.endsWith("ControllerHandler") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
|
||||||
toast.warning(t("tips.controllerUrlPattern"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(values.shellType === "HandlerMethod" || values.shellType === "HandlerFunction") &&
|
|
||||||
(values.urlPattern === "/*" || !values.urlPattern)
|
|
||||||
) {
|
|
||||||
toast.warning(t("tips.handlerUrlPattern"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (values.shellTool === ShellToolType.Custom && !values.shellClassBase64) {
|
|
||||||
toast.warning(t("tips.customShellClass"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onSubmit(values: FormSchema) {
|
|
||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
if (!customValidation(values)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const postData = transformToPostData(values);
|
|
||||||
try {
|
try {
|
||||||
|
customValidation(t, data);
|
||||||
|
const postData = transformToPostData(data);
|
||||||
const response = await fetch(`${env.API_URL}/generate`, {
|
const response = await fetch(`${env.API_URL}/generate`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -105,31 +91,30 @@ function IndexComponent() {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify(postData),
|
body: JSON.stringify(postData),
|
||||||
});
|
});
|
||||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
||||||
if (response.ok) {
|
if (!response.ok) {
|
||||||
const json: GenerateResponse = await response.json();
|
|
||||||
setPackResult(json.packResult);
|
|
||||||
setAllPackResults(json.allPackResults);
|
|
||||||
setGenerateResult(json.generateResult);
|
|
||||||
setPackMethod(values.packingMethod);
|
|
||||||
toast.success(t("success.generated"));
|
|
||||||
} else {
|
|
||||||
const json: APIErrorResponse = await response.json();
|
const json: APIErrorResponse = await response.json();
|
||||||
toast.error(t("errors.generationFailed", { error: json.error }));
|
toast.error(t("errors.generationFailed", { error: json.error }));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
const error = err as Error;
|
const result = (await response.json()) as GenerateResponse;
|
||||||
toast.error(t("errors.generationFailed", { error: error.message }));
|
setGenerateResult(result.generateResult);
|
||||||
|
setPackResult(result.packResult);
|
||||||
|
setAllPackResults(result.allPackResults);
|
||||||
|
setPackMethod(data.packingMethod);
|
||||||
|
toast.success(t("success.generated"));
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(t("errors.generationFailed", { error: (error as Error).message }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col xl:flex-row gap-4 p-4">
|
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col xl:flex-row gap-4 p-4">
|
||||||
<div className="w-full xl:w-1/2 space-y-4">
|
<div className="w-full xl:w-1/2 space-y-4">
|
||||||
<MainConfigCard servers={data?.servers} mainConfig={data?.core} form={form} />
|
<MainConfigCard servers={serverConfig} mainConfig={mainConfig} form={form} />
|
||||||
<PackageConfigCard packerConfig={data?.packers} form={form} />
|
<PackageConfigCard packerConfig={packerConfig} form={form} />
|
||||||
<Button className="w-full" type="submit" disabled={isActionPending}>
|
<Button className="w-full" type="submit" disabled={isActionPending}>
|
||||||
{isActionPending ? <LoaderCircle className="animate-spin" /> : <WandSparklesIcon />}
|
{isActionPending ? <LoaderCircle className="animate-spin" /> : <WandSparklesIcon />}
|
||||||
{t("buttons.generate")}
|
{t("buttons.generate")}
|
||||||
@@ -146,4 +131,4 @@ function IndexComponent() {
|
|||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
|
const queryClient = new QueryClient({
|
||||||
|
defaultOptions: {
|
||||||
|
queries: {
|
||||||
|
staleTime: 1000 * 60 * 5, // 5 minutes
|
||||||
|
retry: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function QueryProvider({ children }: { children: ReactNode }) {
|
||||||
|
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
|
||||||
|
}
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
|
|
||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
// noinspection JSUnusedGlobalSymbols
|
|
||||||
|
|
||||||
// This file was automatically generated by TanStack Router.
|
|
||||||
// You should NOT make any changes in this file as it will be overwritten.
|
|
||||||
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
|
||||||
|
|
||||||
// Import Routes
|
|
||||||
|
|
||||||
import { Route as rootRoute } from "./routes/__root";
|
|
||||||
import { Route as IndexImport } from "./routes/index";
|
|
||||||
|
|
||||||
// Create/Update Routes
|
|
||||||
|
|
||||||
const IndexRoute = IndexImport.update({
|
|
||||||
id: "/",
|
|
||||||
path: "/",
|
|
||||||
getParentRoute: () => rootRoute,
|
|
||||||
} as any);
|
|
||||||
|
|
||||||
// Populate the FileRoutesByPath interface
|
|
||||||
|
|
||||||
declare module "@tanstack/react-router" {
|
|
||||||
interface FileRoutesByPath {
|
|
||||||
"/": {
|
|
||||||
id: "/";
|
|
||||||
path: "/";
|
|
||||||
fullPath: "/";
|
|
||||||
preLoaderRoute: typeof IndexImport;
|
|
||||||
parentRoute: typeof rootRoute;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create and export the route tree
|
|
||||||
|
|
||||||
export interface FileRoutesByFullPath {
|
|
||||||
"/": typeof IndexRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileRoutesByTo {
|
|
||||||
"/": typeof IndexRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileRoutesById {
|
|
||||||
__root__: typeof rootRoute;
|
|
||||||
"/": typeof IndexRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileRouteTypes {
|
|
||||||
fileRoutesByFullPath: FileRoutesByFullPath;
|
|
||||||
fullPaths: "/";
|
|
||||||
fileRoutesByTo: FileRoutesByTo;
|
|
||||||
to: "/";
|
|
||||||
id: "__root__" | "/";
|
|
||||||
fileRoutesById: FileRoutesById;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RootRouteChildren {
|
|
||||||
IndexRoute: typeof IndexRoute;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rootRouteChildren: RootRouteChildren = {
|
|
||||||
IndexRoute: IndexRoute,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const routeTree = rootRoute._addFileChildren(rootRouteChildren)._addFileTypes<FileRouteTypes>();
|
|
||||||
|
|
||||||
/* ROUTE_MANIFEST_START
|
|
||||||
{
|
|
||||||
"routes": {
|
|
||||||
"__root__": {
|
|
||||||
"filePath": "__root.tsx",
|
|
||||||
"children": [
|
|
||||||
"/"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"/": {
|
|
||||||
"filePath": "index.tsx"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ROUTE_MANIFEST_END */
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { createBrowserRouter } from "react-router-dom";
|
||||||
|
import { env } from "@/config";
|
||||||
|
import RootLayout from "@/components/layouts/root-layout";
|
||||||
|
import IndexPage from "@/pages";
|
||||||
|
|
||||||
|
export const router = createBrowserRouter(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
element: <RootLayout />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <IndexPage />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
{
|
||||||
|
basename: env.BASE_PATH,
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -1,5 +1,27 @@
|
|||||||
import { FormSchema } from "@/types/schema.ts";
|
import { FormSchema } from "@/types/schema.ts";
|
||||||
import { InjectorConfig, ShellConfig, ShellToolConfig } from "@/types/shell.ts";
|
import { InjectorConfig, ShellConfig, ShellToolConfig, ShellToolType } from "@/types/shell.ts";
|
||||||
|
import { TFunction } from "i18next";
|
||||||
|
|
||||||
|
export function customValidation(t: TFunction<"translation", undefined>, values: FormSchema) {
|
||||||
|
if (values.shellType.endsWith("Servlet") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
||||||
|
throw new Error(t("tips.servletUrlPattern"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.shellType.endsWith("ControllerHandler") && (values.urlPattern === "/*" || !values.urlPattern)) {
|
||||||
|
throw new Error(t("tips.controllerUrlPattern"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(values.shellType === "HandlerMethod" || values.shellType === "HandlerFunction") &&
|
||||||
|
(values.urlPattern === "/*" || !values.urlPattern)
|
||||||
|
) {
|
||||||
|
throw new Error(t("tips.handlerUrlPattern"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.shellTool === ShellToolType.Custom && !values.shellClassBase64) {
|
||||||
|
throw new Error(t("tips.customShellClass"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function transformToPostData(formValue: FormSchema) {
|
export function transformToPostData(formValue: FormSchema) {
|
||||||
const shellConfig: ShellConfig = {
|
const shellConfig: ShellConfig = {
|
||||||
|
|||||||
+1
-2
@@ -1,12 +1,11 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import tailwindcss from "@tailwindcss/vite";
|
import tailwindcss from "@tailwindcss/vite";
|
||||||
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
|
|
||||||
import react from "@vitejs/plugin-react";
|
import react from "@vitejs/plugin-react";
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [TanStackRouterVite({ autoCodeSplitting: true }), react(), tailwindcss()],
|
plugins: [react(), tailwindcss()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
"@": path.resolve(__dirname, "./src"),
|
"@": path.resolve(__dirname, "./src"),
|
||||||
|
|||||||
Reference in New Issue
Block a user