chore(web ui):ref tunnel modules (#2331)

pull/2334/head
xudaotutou 2 years ago committed by GitHub
parent aaeb2d2fd4
commit b252ca2b1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,2 +1,3 @@
# NODE_ENV=production
VITE_AGENT=true
VITE_ARTHAS_PORT=7777
VITE_ARTHAS_PROXY_PORT=8080

@ -1,2 +1,3 @@
# NODE_ENV=production
VITE_AGENT=false
VITE_ARTHAS_PORT=8563
VITE_ARTHAS_PROXY_PORT=8563

@ -6,7 +6,7 @@ declare module '*.vue' {
export default component
}
interface ImportMetaEnv {
readonly VITE_AGENT:string
readonly VITE_ARTHAS_PORT:string
}
interface ImportMeta {

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 542 B

After

Width:  |  Height:  |  Size: 542 B

@ -1,21 +1,31 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { onMounted, ref, computed } from "vue";
import { Terminal } from "xterm"
import { FitAddon } from 'xterm-addon-fit';
import { WebglAddon } from "xterm-addon-webgl"
import { MenuAlt2Icon } from "@heroicons/vue/outline"
import fullPic from "~/assert/fullsc.png"
import arthasLogo from "~/assert/arthas.png"
const { isTunnel = false } = defineProps<{
isTunnel?: boolean
}>()
let ws: WebSocket | undefined;
let intervalReadKey = -1
const DEFAULT_SCROLL_BACK = 1000
const MAX_SCROLL_BACK = 9999999
const MIN_SCROLL_BACK = 1
const ARTHAS_PORT = '8563'
const ARTHAS_PORT = isTunnel ? "7777" : "8563"
const ip = ref("")
const port = ref('')
const iframe = ref(true)
const fullSc = ref(true)
const agentID = ref('')
const isTunnel = import.meta.env.VITE_AGENT === 'true'
const outputHerf = computed(() => {
console.log(agentID.value)
return isTunnel?`proxy/${agentID.value}/arthas-output/`:`/arthas-output/`
})
// const isTunnel = import.meta.env.MODE === 'tunnel'
const fitAddon = new FitAddon();
const webglAddon = new WebglAddon();
let xterm = new Terminal({ allowProposedApi: true })
@ -23,6 +33,7 @@ let xterm = new Terminal({ allowProposedApi: true })
onMounted(() => {
ip.value = getUrlParam('ip') ?? window.location.hostname;
port.value = getUrlParam('port') ?? ARTHAS_PORT;
if (isTunnel) agentID.value = getUrlParam("agentId") ?? ""
let _iframe = getUrlParam('iframe')
if (_iframe && _iframe.trim() !== 'false') iframe.value = false
@ -42,12 +53,22 @@ function getUrlParam(name: string) {
return urlparam.get(name)
}
function getWsUri() {
const host = `${ip.value}:${port.value}`
if (!isTunnel) return `ws://${host}/ws`;
const path = getUrlParam("path") ?? 'ws'
const _targetServer = getUrlParam("targetServer")
let protocol = location.protocol === 'https:' ? 'wss://' : 'ws://';
const uri = `${protocol}${host}/${encodeURIComponent(path)}?method=connectArthas&id=${agentID.value}`
if (_targetServer != null) {
return uri + '&targetServer=' + encodeURIComponent(_targetServer);
}
return uri
}
/** init websocket **/
function initWs(silent: boolean) {
let path = 'ws://' + ip.value + ':' + port.value + '/ws';
console.log(path)
ws = new WebSocket(path);
let uri = getWsUri()
ws = new WebSocket(uri);
ws.onerror = function () {
ws ?? ws!.close();
ws = undefined;
@ -69,12 +90,21 @@ function initWs(silent: boolean) {
}
};
ws?.send(JSON.stringify({ action: 'resize', cols, rows }));
window.setInterval(function () {
intervalReadKey = window.setInterval(function () {
if (ws != null && ws.readyState === 1) {
ws.send(JSON.stringify({ action: 'read', data: "" }));
}
}, 30000);
}
ws.onclose = function (message) {
if (intervalReadKey != -1) {
window.clearInterval(intervalReadKey)
intervalReadKey = -1
}
if (message.code === 2000) {
alert(message.reason);
}
};
}
/** init xterm **/
@ -103,18 +133,31 @@ function isValidNumber(scrollNumber: number) {
scrollNumber <= MAX_SCROLL_BACK;
}
/** begin connect **/
function startConnect(silent: boolean = false) {
const connectGuard = (silent: boolean): boolean => {
if (ip.value.trim() === '' || port.value.trim() === '') {
alert('Ip or port can not be empty');
return;
return false;
}
if (isTunnel && agentID.value == '') {
if (silent) {
return false;
}
alert('AgentId can not be empty');
return false;
}
if (ws) {
alert('Already connected');
return;
return false;
}
// init webSocket
initWs(silent);
return true
}
/** begin connect **/
function startConnect(silent: boolean = false) {
if (connectGuard(silent)) {
// init webSocket
initWs(silent);
}
}
function disconnect() {
@ -126,7 +169,6 @@ function disconnect() {
xterm.dispose();
fitAddon.dispose()
webglAddon.dispose()
// $('#fullSc').hide();
fullSc.value = false
alert('Connection was closed successfully!');
} catch {
@ -157,16 +199,37 @@ function requestFullScreen(element: HTMLElement) {
}
}
</script>
<template>
<div class="flex flex-col h-[100vh] resize-none">
<nav v-if="iframe" class="navbar bg-base-100 flex-row">
<div class="flex-1">
<a href="https://github.com/alibaba/arthas" target="_blank" title="" class="mr-2 w-20"><img src="/arthas.png"
alt="Arthas" title="Welcome to Arthas web console" class=""></a>
<ul class="menu menu-horizontal p-0">
<div class="flex flex-col h-[100vh] w-[100vw] resize-none">
<nav v-if="iframe" class="navbar bg-base-100 md:flex-row flex-col w-[100vw]">
<div class="navbar-start">
<div class="dropdown dropdown-start 2xl:hidden">
<label tabindex="0" class="btn btn-ghost btn-sm">
<MenuAlt2Icon class="w-6 h-6"></MenuAlt2Icon>
</label>
<ul tabindex="0" class="dropdown-content menu shadow bg-base-100">
<li>
<a class="hover:text-sky-500 dark:hover:text-sky-400 text-sm" href="https://arthas.aliyun.com/doc"
target="_blank">Documentation
<span class="sr-only">(current)</span></a>
</li>
<li>
<a class="hover:text-sky-500 dark:hover:text-sky-400 text-sm"
href="https://arthas.aliyun.com/doc/arthas-tutorials.html" target="_blank">Online
Tutorials</a>
</li>
<li>
<a class="hover:text-sky-500 dark:hover:text-sky-400 text-sm" href="https://github.com/alibaba/arthas"
target="_blank">Github</a>
</li>
</ul>
</div>
<a href="https://github.com/alibaba/arthas" target="_blank" title="" class="mr-2 w-20"><img
:src="arthasLogo" alt="Arthas" title="Welcome to Arthas web console"></a>
<ul class="menu menu-vertical 2xl:menu-horizontal hidden">
<li>
<a class="hover:text-sky-500 dark:hover:text-sky-400 text-sm" href="https://arthas.aliyun.com/doc"
target="_blank">Documentation
@ -182,9 +245,14 @@ function requestFullScreen(element: HTMLElement) {
target="_blank">Github</a>
</li>
</ul>
</div>
<form class="navbar-end">
<div class="flex">
<div class="navbar-center ">
<div class=" xl:flex-row form-control"
:class="{
'xl:flex-row':isTunnel,
'lg:flex-row':!isTunnel
}">
<label class="input-group input-group-sm mr-2">
<span>IP</span>
<input type="text" placeholder="please enter ip address" class="input input-bordered input-sm "
@ -194,28 +262,35 @@ function requestFullScreen(element: HTMLElement) {
<span>Port</span>
<input type="text" placeholder="please enter port" class="input input-sm input-bordered" v-model="port" />
</label>
<label v-if="isTunnel" class="input-group input-group-sm mr-2">
<span>AgentId</span>
<input type="text" placeholder="please enter AgentId" class="input input-sm input-bordered"
v-model="agentID" />
</label>
</div>
<div class="btn-group btn-group-horizontal">
</div>
<div class="navbar-end">
<div class="btn-group 2xl:btn-group-horizontal btn-group-horizontal"
:class="{
'md:btn-group-vertical':isTunnel
}">
<button
class="btn btn-sm bg-secondary hover:bg-secondary-focus border-none text-secondary-content focus:bg-secondary-focus normal-case"
@click.prevent="startConnect(true)">Connect</button>
<button
class="btn btn-sm bg-secondary hover:bg-secondary-focus border-none text-secondary-content focus:bg-secondary-focus normal-case"
@click.prevent="disconnect">Disconnect</button>
<a v-if="!isTunnel" class="btn btn-sm bg-secondary hover:bg-secondary-focus border-none text-secondary-content focus:bg-secondary-focus normal-case"
href="arthas-output/" target="_blank">Arthas Output</a>
<a class="btn btn-sm bg-secondary hover:bg-secondary-focus border-none text-secondary-content focus:bg-secondary-focus normal-case"
:href="outputHerf" target="_blank">Arthas Output</a>
</div>
</form>
</div>
</nav>
<div class="w-full h-0 flex-auto bg-black overscroll-auto" id="terminal-card">
<!-- <div class="h-full overflow-visible" id="terminal-card"> -->
<div id="terminal" class="w-full h-full"></div>
<!-- </div> -->
</div>
<div title="fullscreen" id="fullSc" class="fullSc" v-if="fullSc">
<button id="fullScBtn" @click="xtermFullScreen"><img src="/fullsc.png"></button>
<button id="fullScBtn" @click="xtermFullScreen"><img :src="fullPic"></button>
</div>
</div>
</template>

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Arthas Tutorials</title>
</head>
<body>
<div id="app">
</div>
<script src="./src/agents.ts" type="module"></script>
</body>
</html>

@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Arthas Tutorials</title>
</head>
<body>
<div id="app">
</div>
<script src="./src/apps.ts" type="module"></script>
</body>
</html>

@ -0,0 +1,60 @@
<script setup lang="ts">
import { onMounted, reactive } from 'vue';
type AgentId = string
const agentInfos: ([AgentId, AgentInfo])[] = reactive([])
function getUrlParam(name: string) {
const urlparam = new URLSearchParams(window.location.search)
return urlparam.get(name)
}
function tunnelWebConsoleLink(agentId: string, targetServer: string) {
return `/?targetServer=${targetServer}&agentId=${agentId}`;
}
const fetchMyApps = () => {
const appName = getUrlParam("app") ?? ""
let url = `/api/tunnelAgentInfo?app=${appName}`
fetch(url)
.then((response) => response.json())
.then((data: Record<AgentId, AgentInfo>) => {
for (const key in data) {
agentInfos.push(
[key, data[key] as AgentInfo]
)
}
})
.catch((error) => console.error('api error ' + error))
}
onMounted(() => {
fetchMyApps()
})
</script>
<template>
<table class="table table-normal w-[100vw]">
<thead>
<tr >
<th class="normal-case">IP</th>
<th class="normal-case">AgentId</th>
<th class="normal-case">Version</th>
</tr>
</thead>
<tbody>
<tr v-for="(agentInfoRecord) in agentInfos" :key="agentInfoRecord[0]" class="hover">
<td>
<a class="btn btn-primary btn-sm"
:href="tunnelWebConsoleLink(agentInfoRecord[0], agentInfoRecord[1].clientConnectHost)">{{
agentInfoRecord[1].host
}}</a>
</td>
<td>
{{ agentInfoRecord[0] }}
</td>
<td>
{{ agentInfoRecord[1].arthasVersion }}
</td>
</tr>
</tbody>
</table>
</template>

@ -0,0 +1,42 @@
<script setup lang="ts">
import { onMounted, reactive } from 'vue';
const apps: string[] = reactive([])
function fetchMyApps() {
fetch('/api/tunnelApps')
.then((response) => response.json())
.then((data: string[]) => {
data.length > 0 && data.forEach(app => apps.push(app))
})
.catch((error) => {
console.error('api error ' + error)
})
}
function detailLink(appName: string) {
return "agents.html?app=" + appName;
}
onMounted(() => {
fetchMyApps()
})
</script>
<template>
<table class="table w-[100vw] table-normal">
<thead>
<tr>
<th class="normal-case">name of application</th>
</tr>
</thead>
<tbody>
<tr v-for="app in apps" :key="app" class="hover">
<td>
<a class="btn btn-primary btn-sm normal-case" :href="detailLink(app)">{{ app }}</a>
</td>
</tr>
</tbody>
</table>
</template>
<style scoped>
</style>

@ -0,0 +1,6 @@
import { createApp } from "vue";
import App from "./Agent.vue";
const app = createApp(App);
import "~/main.css";
app
.mount("#app");

@ -0,0 +1,5 @@
import App from "./Apps.vue"
import { createApp } from "vue"
import "~/main.css";
createApp(App)
.mount("#app");

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@ -0,0 +1,7 @@
import { createApp, h } from "vue";
import App from "~/component/Console.vue";
const app = createApp(h(App, { isTunnel: true }));
import "xterm/css/xterm.css";
import "~/main.css";
app
.mount("#app");

@ -0,0 +1,6 @@
type AgentInfo = {
clientConnectHost:string,
host:string,
port:number,
arthasVersion:string
}

@ -0,0 +1,16 @@
<!doctype html>
<html lang="en" data-theme="corporate">
<head>
<meta charset="utf-8">
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Arthas Console</title>
</head>
<body>
<div id="app"></div>
<script src="./src/main.ts" type="module"></script>
</body>
</html>

@ -1,7 +1,7 @@
import { createApp } from "vue";
import App from "./App.vue";
import App from "~/component/Console.vue";
const app = createApp(App);
import "xterm/css/xterm.css"
import "./main.css"
import "~/main.css"
app
.mount("#app");

@ -18,14 +18,9 @@ onBeforeUnmount(() => {
<template>
<div class=" h-screen flex flex-col">
<nav-header class="h-[10vh]"></nav-header>
<div class=" flex-auto h-[90vh] overflow-auto">
<div class="flex flex-row h-full">
<!-- <nav-aside ></nav-aside> -->
<div class="flex-auto overflow-auto h-[90vh] w-[90vw]">
<div class=" flex-auto h-[90vh] overflow-auto w-[100vw]">
<router-view>
</router-view>
</div>
</div>
</div>
</div>

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useMachine } from '@xstate/vue';
import { computed, onBeforeMount, Ref, ref, watchEffect } from 'vue';
import { RefreshIcon, LogoutIcon, LoginIcon, MenuIcon, XCircleIcon } from '@heroicons/vue/outline';
import { RefreshIcon, LogoutIcon, LoginIcon, MenuIcon, MenuAlt2Icon } from '@heroicons/vue/outline';
import { fetchStore } from '@/stores/fetch';
import machine from "@/machines/consoleMachine"
import { publicStore } from '@/stores/public';
@ -10,6 +10,7 @@ import { PuzzleIcon, TerminalIcon, ViewGridIcon } from "@heroicons/vue/outline"
import { DesktopComputerIcon } from "@heroicons/vue/solid"
import { useRoute, useRouter } from 'vue-router';
import permachine from '@/machines/perRequestMachine';
import pic from "~/assert/arthas.png"
const fetchM = useMachine(machine)
const publicS = publicStore()
const { send } = fetchM
@ -130,9 +131,9 @@ const tabs = [
},
{
name:'terminal',
url:'terminal',
icon:TerminalIcon
name: 'terminal',
url: 'terminal',
icon: TerminalIcon
}
]
@ -148,23 +149,38 @@ const toNext = (url: string) => {
window.open("/", "_blank")
} else router.push(url)
}
</script>
<template>
<nav class=" h-[10vh] border-b-2 navbar">
<div class=" navbar-start flex items-stretch ">
<!-- <div class=" indicator mx-3"> -->
<nav class=" h-[10vh] border-b-2 navbar bg-base-100">
<div class=" navbar-start flex items-stretch">
<div class="dropdown dropdown-start hover xl:hidden">
<label tabindex="0" class="btn btn-ghost m-1">
<MenuAlt2Icon class="w-6 h-6"></MenuAlt2Icon>
</label>
<ul tabindex="0" class="menu menu-vertical dropdown-content bg-base-100 shadow rounded-box">
<li v-for="(tab, idx) in tabs" :key="idx" @click="toNext(tab.url)">
<a :class="{ 'bg-primary text-primary-content': routePath.includes(tab.url), }">
<component :is="tab.icon" class="w-4 h-4" />
{{
tab.name
}}
</a>
</li>
</ul>
</div>
<a class="flex items-center justify-center mx-2" href="https://arthas.aliyun.com/doc/commands.html"
target="_blank">
<img src="/arthas.png" alt="logo" class="w-32" />
<img :src="pic" alt="logo" class="w-32" />
</a>
<span class="badge badge-ghost self-end text-sm">v{{ version }}</span>
<!-- </div> -->
<span class="badge badge-ghost self-end badge-sm">v{{ version }}</span>
</div>
<div class="navbar-center">
<ul class="menu menu-horizontal p-0">
<ul class="menu menu-horizontal hidden xl:flex">
<li v-for="(tab, idx) in tabs" :key="idx" @click="toNext(tab.url)">
<a class="break-all" :class="{ 'bg-primary text-primary-content': routePath.includes(tab.url), }">
<a :class="{ 'bg-primary text-primary-content': routePath.includes(tab.url), }">
<component :is="tab.icon" class="w-4 h-4" />
{{
tab.name
@ -181,18 +197,16 @@ const toNext = (url: string) => {
<MenuIcon class=" w-6 h-6"></MenuIcon>
</label>
<ul tabindex="0" class="menu dropdown-content p-2 shadow-xl bg-base-200 rounded-box w-40">
<li class="" v-for="(v,i) in tools" :key="i">
<a @click.prevent="v[1]">{{v[0]}}</a>
<li class="" v-for="(v, i) in tools" :key="i">
<a @click.prevent="v[1]">{{ v[0] }}</a>
</li>
</ul>
</div>
<button class=" btn btn-ghost"
:class="{ 'btn-primary': !fetchS.online, 'btn-error': fetchS.online }">
<button class=" btn btn-ghost" :class="{ 'btn-primary': !fetchS.online, 'btn-error': fetchS.online }">
<LogoutIcon class="h-6 w-6" @click="logout" v-if="fetchS.online" />
<login-icon class="h-6 w-6" @click="login" v-else />
</button>
<button class="btn-ghost btn"
@click="reset">
<button class="btn-ghost btn" @click="reset">
<refresh-icon class="h-6 w-6" :class="restBtnclass" />
</button>
</div>

@ -1,5 +1,5 @@
import { createApp } from "vue";
import "./index.css";
import "~/main.css"
import router from "./router/index";
import { createPinia } from "pinia";
import App from "./App.vue";

@ -0,0 +1,3 @@
export default function transformStackTrace(trace: StackTrace) {
return `${trace.className}.${trace.methodName} (${trace.fileName}: ${trace.lineNumber})`;
}

@ -441,52 +441,63 @@ onBeforeUnmount(async () => {
</script>
<template>
<div class="p-2 pointer-events-auto flex flex-col h-full">
<div class="input-btn-style mb-4 h-32 flex flex-wrap flex-col items-start overflow-auto min-h-[6rem]">
<div v-for="(cv, ci) in runtimeInfo" :key="ci" class="flex mb-1 pr-2">
<span class="bg-primary-focus text-primary-content border border-primary-focus w-44 px-2 rounded-l">
{{ cv[0] }}
</span>
<span class="bg-base-200 border border-primary-focus rounded-r px-2 flex-1">
{{cv[1]}}
<div class="p-2 pointer-events-auto h-full overflow-auto">
<div class="card bg-base-100 border mb-4 compact h-auto">
<div class="card-body flex-wrap flex-row">
<span v-for="(cv, ci) in runtimeInfo" :key="ci" class="badge badge-outline badge-primary">
{{ cv[0] }}:
{{ cv[1] }}
</span>
</div>
</div>
<!-- <CmdResMenu title="threads" :map="threads" class="w-full flex justify-center" /> -->
<div class="flex justify-evenly mb-4 flex-1 h-80">
<div id="heapMemory" class="w-80 h-80 flex-1 input-btn-style mr-4"></div>
<div id="nonheapMemory" class="w-80 h-80 flex-1 input-btn-style mr-4"></div>
<div id="bufferPoolMemory" class="w-80 h-80 flex-1 input-btn-style"></div>
<div class="card border mr-4 flex-1 bg-base-100">
<div id="heapMemory" class="w-80 h-80 card-body "></div>
</div>
<div class="card border mr-4 flex-1 bg-base-100">
<div id="nonheapMemory" class="w-80 h-80 card-body"></div>
</div>
<div class="card border flex-1 bg-base-100">
<div id="bufferPoolMemory" class="w-80 h-80 card-body"></div>
</div>
</div>
<div class="w-full flex justify-start items-start flex-1">
<div id="gc-info" class="w-[40rem] h-80 input-btn-style p-2 mr-4"></div>
<div class="input-btn-style flex-1 h-80 overflow-auto w-0">
<div class="flex justify-end mb-2">
<div class="btn-group">
<button class="btn btn-sm btn-outline" @click="decrease">-</button>
<button class="btn btn-sm btn-outline border-x-0" @click="setPri">limit:{{pri}}</button>
<button class="btn btn-sm btn-outline" @click="increase">+</button>
<div class="card bg-base-100 border mr-4">
<div id="gc-info" class="w-[40rem] h-80 card-body p-2 "></div>
</div>
<div class="card flex-1 h-80 overflow-auto w-0 border bg-base-100">
<div class="card-body">
<div class="flex justify-end mb-2">
<div class="btn-group">
<button class="btn btn-sm btn-outline" @click="decrease">-</button>
<button class="btn btn-sm btn-outline border-x-0" @click="setPri">limit:{{ pri }}</button>
<button class="btn btn-sm btn-outline" @click="increase">+</button>
</div>
</div>
<div class="overflow-x-auto">
<table class="table table-compact w-full">
<thead>
<tr>
<th></th>
<th v-for="(v, i) in keyList" :key="i" class="normal-case">{{ v }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResults" :key="i" class="hover">
<th>{{ i + 1 }}</th>
<td v-for="(key, j) in keyList" :key="j">
{{ map.get(key) }}
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="overflow-x-auto">
<table class="table table-compact w-full">
<thead>
<tr>
<th></th>
<th v-for="(v,i) in keyList" :key="i" class="normal-case">{{v}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResults" :key="i" class="hover">
<th>{{i + 1}}</th>
<td v-for="(key,j) in keyList" :key="j">
{{map.get(key)}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

@ -7,9 +7,6 @@ const routes: { cmd: string, url: string }[] = [
}, {
cmd: "classInfo",
url: "classInfo"
// }, {
// cmd: "perfcounter",
// url: "perfcounter"
}, {
cmd: "classLoader",
url: "classLoader"

@ -6,14 +6,11 @@ import { fetchStore } from '@/stores/fetch';
import { useMachine, useInterpret } from '@xstate/vue';
import { onBeforeMount, onBeforeUnmount, reactive, ref } from 'vue';
import Enhancer from '@/components/show/Enhancer.vue';
import {transfromStore} from "@/stores/resTransform"
import transformStackTrace from '@/utils/transform';
const fetchM = useInterpret(permachine)
const pollingM = useMachine(machine)
const fetchS = fetchStore()
// const publicS = publicStore()
const transS = transfromStore()
const { getCommonResEffect } = fetchS
// const {getCommonResEffect} = publicStore()
const loop = fetchS.pullResultsLoop(pollingM)
const tableResults = reactive([] as Map<string, string>[])
@ -26,8 +23,8 @@ const keyList = [
"classloader",
"threadId",
"threadName",]
// const enhancer = reactive(new Map())
const enhancer = ref(undefined as EnchanceResult | undefined)
getCommonResEffect(pollingM, body => {
if (body.results.length > 0) {
body.results.forEach(result => {
@ -40,7 +37,7 @@ getCommonResEffect(pollingM, body => {
let val: string | string[] = ""
if (k === "stackTrace") {
let stackTrace = result[k]
val = stackTrace.map((trace) => transS.transformStackTrace(trace))
val = stackTrace.map((trace) => transformStackTrace(trace))
} else {
val = result[k as Exclude<keyof typeof result, "jobId" | "type" | "stackTrace">].toString()
}
@ -58,10 +55,8 @@ getCommonResEffect(pollingM, body => {
})
onBeforeMount(() => {
// fetchM.send("INIT")
pollingM.send("INIT")
fetchS.asyncInit()
// loop.open()
})
onBeforeUnmount(() => {
loop.close()

@ -7,7 +7,6 @@ import CmdResMenu from '@/components/show/CmdResMenu.vue';
import { fetchStore } from '@/stores/fetch';
import { interpret } from 'xstate';
import permachine from '@/machines/perRequestMachine';
const classInfoM = useMachine(machine)
const classMethodInfoM = useMachine(machine)
const dumpM = useMachine(machine)
const classDetailMap = reactive(new Map<string, string[]>())

@ -1,12 +1,10 @@
<script setup lang="ts">
import { computed, onBeforeMount, onUnmounted, reactive, ref } from 'vue';
import { Disclosure, DisclosureButton, DisclosurePanel } from '@headlessui/vue';
import { computed, onBeforeMount, reactive, ref } from 'vue';
import { publicStore } from "@/stores/public"
import { fetchStore } from '@/stores/fetch';
import { interpret } from 'xstate';
import CmdResMenu from '@/components/show/CmdResMenu.vue';
import transformMachine from '@/machines/transformConfigMachine';
// import ClassInput from '@/components/input/ClassInput.vue';
import permachine from '@/machines/perRequestMachine';
import Tree from '@/components/show/Tree.vue';
const fetchS = fetchStore()
@ -208,131 +206,135 @@ const resetClassloader = () => {
<template>
<div class="flex flex-col h-full justify-between">
<div class="flex h-[40vh]">
<div class="input-btn-style h-full p-4 mb-2 flex flex-col transition-all duration-500" :class='{
"w-full":loaderCache.hash === "",
"w-2/3":loaderCache.hash !== ""
<div class="card rounded-box border transition-all duration-500 bg-base-100 mr-2 " :class='{
"w-full": loaderCache.hash === "",
"w-2/3": loaderCache.hash !== ""
}'>
<!-- 后置为了让用户能注意到右上角的refreshicon -->
<div class="h-[5vh] mb-4 justify-end flex">
<button @click="resetClassloader" class="btn btn-primary btn-sm mr-1">reset</button>
<button @click="getClassLoaderTree" class="btn btn-primary btn-sm">refresh</button>
</div>
<div class="card-body h-full p-4 mb-2 ">
<!-- 后置为了让用户能注意到右上角的refreshicon -->
<div class="h-[5vh] mb-4 justify-end flex">
<button @click="resetClassloader" class="btn btn-primary btn-sm mr-1">reset</button>
<button @click="getClassLoaderTree" class="btn btn-primary btn-sm">refresh</button>
</div>
<div class="overflow-auto w-full flex-1">
<div v-for="(tree,i) in classLoaderTree" :key="i">
<Tree :root="tree">
<template #meta="{ data, active }">
<!-- <div class="flex items-center"> -->
<div class="bg-info px-2 rounded-r rounded-br mr-2 text-info-content" :class='{
"hover:opacity-50":active,
"bg-success text-success-content":loaderCache.hash=== data[2]
}'>
{{data[1]}}
<!-- </div> -->
</div>
</template>
<template #others="{data}">
<div class="items-center flex">
<div class="mr-2">
<span class="bg-primary-focus text-primary-content border border-primary-focus px-2 rounded-l ">
count :
</span>
<span class="bg-base-200 border border-primary-focus rounded-r px-1 ">
{{data[0]}}
</span>
<div class="overflow-auto w-full flex-1">
<div v-for="(tree, i) in classLoaderTree" :key="i">
<Tree :root="tree">
<template #meta="{ data, active }">
<!-- <div class="flex items-center"> -->
<div class="bg-info px-2 rounded-r rounded-br mr-2 text-info-content" :class='{
"hover:opacity-50": active,
"bg-success text-success-content": loaderCache.hash === data[2]
}'>
{{ data[1] }}
<!-- </div> -->
</div>
<div class="mr-2">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
hash :
</span>
<span class="bg-base-200 rounded-r flex-1 px-1 border border-primary-focus">
{{data[2]}}
</span>
</template>
<template #others="{ data }">
<div class="items-center flex">
<div class="mr-2">
<span class="bg-primary-focus text-primary-content border border-primary-focus px-2 rounded-l ">
count :
</span>
<span class="bg-base-200 border border-primary-focus rounded-r px-1 ">
{{ data[0] }}
</span>
</div>
<div class="mr-2">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
hash :
</span>
<span class="bg-base-200 rounded-r flex-1 px-1 border border-primary-focus">
{{ data[2] }}
</span>
</div>
<!-- <div class="">count:{{data[0]}}</div> -->
<button @click="selectClassLoader({ name: data[1], hash: data[2], count: data[0] })"
class="btn btn-primary btn-xs btn-outline opacity-0 group-hover:opacity-100"
v-if="data[2] !== 'null'">
select classloader
</button>
</div>
<!-- <div class="">count:{{data[0]}}</div> -->
<button @click="selectClassLoader({name:data[1],hash:data[2],count:data[0]})"
class="btn btn-primary btn-xs btn-outline opacity-0 group-hover:opacity-100"
v-if="data[2]!== 'null'">
select classloader
</button>
</div>
</template>
</Tree>
</template>
</Tree>
</div>
</div>
</div>
</div>
<div class=" ml-2 overflow-y-scroll transition-all duration-500" :class='{
"w-0":loaderCache.hash === "",
"input-btn-style w-1/3":loaderCache.hash !==""
<div class="card rounded-box border bg-base-100" :class='{
"w-0 border-none": loaderCache.hash === "",
"input-btn-style w-1/3": loaderCache.hash !== ""
}'>
<div class="card-body ml-2 overflow-y-scroll transition-all duration-500">
<div class="mb-2">
<div class="overflow-auto">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
selected classLoader:
</span>
<span class="bg-base-200 rounded-r px-1 border border-primary-focus">
{{loaderCache.name}}
</span>
</div>
<div class="mr-2">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
loadedcount :
</span>
<span class="bg-base-200 rounded-r px-1 border border-primary-focus">
{{loaderCache.count}}
</span>
</div>
<div class="mr-2">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
hash :
</span>
<span class="bg-base-200 rounded-r px-1 border border-primary-focus">
{{loaderCache.hash}}
</span>
<div class="mb-2">
<div class="overflow-auto">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
selected classLoader:
</span>
<span class="bg-base-200 rounded-r px-1 border border-primary-focus">
{{ loaderCache.name }}
</span>
</div>
<div class="mr-2">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
loadedcount :
</span>
<span class="bg-base-200 rounded-r px-1 border border-primary-focus">
{{ loaderCache.count }}
</span>
</div>
<div class="mr-2">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
hash :
</span>
<span class="bg-base-200 rounded-r px-1 border border-primary-focus">
{{ loaderCache.hash }}
</span>
</div>
</div>
</div>
<template v-if="loaderCache.hash.trim() !== ''">
<div class="flex mb-2 w-full">
<div class=" cursor-default
<template v-if="loaderCache.hash.trim() !== ''">
<div class="flex mb-2 w-full">
<div class=" cursor-default
flex-auto
overflow-hidden rounded-lg bg-white text-left border
focus-within:outline outline-2
hover:shadow-md transition mr-2">
<input class="w-full border-none py-2 pl-3 pr-10 leading-5 text-gray-900 focus-visible:outline-none"
v-model="classVal" />
<input class="w-full border-none py-2 pl-3 pr-10 leading-5 text-gray-900 focus-visible:outline-none"
v-model="classVal" />
</div>
<button @click="loadClass" class="btn btn-primary btn-sm btn-outline">load class</button>
</div>
<button @click="loadClass" class="btn btn-primary btn-sm btn-outline">load class</button>
</div>
<div class="flex w-full">
<div class=" cursor-default
<div class="flex w-full">
<div class=" cursor-default
flex-auto
overflow-hidden rounded-lg bg-white text-left border
focus-within:outline outline-2
hover:shadow-md transition mr-2">
<input class="w-full border-none py-2 pl-3 pr-10 leading-5 text-gray-900 focus-visible:outline-none"
v-model="resourceVal" />
<input class="w-full border-none py-2 pl-3 pr-10 leading-5 text-gray-900 focus-visible:outline-none"
v-model="resourceVal" />
</div>
<button @click="loadResource" class="btn btn-primary btn-sm btn-outline">load resource</button>
</div>
<button @click="loadResource" class="btn btn-primary btn-sm btn-outline">load resource</button>
</div>
<div class="h-0 border my-2"></div>
<div class="flex justify-between">
<h3 class="text-xl flex-1 flex justify-center">urls</h3><button class="btn btn-primary btn-sm"
@click="getUrlStats">refresh</button>
</div>
<ul class="mt-2 w-full flex flex-col">
<li v-for="(url,i) in selectedClassLoadersUrlStats" :key="i" class="bg-blue-200 mb-2 p-2 break-all w-full">
{{url}}</li>
</ul>
</template>
<!-- </div> -->
<div class="h-0 border my-2"></div>
<div class="flex justify-between">
<h3 class="text-xl flex-1 flex justify-center">urls</h3><button class="btn btn-primary btn-sm"
@click="getUrlStats">refresh</button>
</div>
<ul class="mt-2 w-full flex flex-col">
<li v-for="(url, i) in selectedClassLoadersUrlStats" :key="i"
class="bg-blue-200 mb-2 p-2 break-all w-full">
{{ url }}</li>
</ul>
</template>
<!-- </div> -->
</div>
</div>
</div>
<!-- 下面的3格 -->
<div class="w-full flex-auto flex h-[40vh] mt-2">
<div class="input-btn-style w-1/3 mr-2 h-full flex">
<div class="overflow-y-scroll h-ful w-full">
<div class="card w-1/3 mr-2 bg-base-100 border">
<div class="card-body overflow-y-scroll">
<div class=" mb-2 flex items-center justify-end">
<h3 class="text-xl flex-1 flex justify-center">urlStats</h3>
<button class="btn btn-primary btn-sm" @click="getAllUrlStats">refresh</button>
@ -341,38 +343,40 @@ const resetClassloader = () => {
<CmdResMenu :title="v[0]" :map="v[1]" button-width="w-full" :button-accent="v[2] === loaderCache.hash">
</CmdResMenu>
</div>
</div>
</div>
<div class="flex flex-col h-full w-2/3">
<div class="input-btn-style w-full mr-2 h-full">
<div class="overflow-auto flex-1 h-full">
<div class="flex justify-end mb-2">
<button class="btn btn-primary btn-sm" @click="getCategorizedByClassType">refresh</button>
</div>
<div class="overflow-auto">
<table class="table w-full table-compact">
<thead>
<tr>
<th></th>
<th class=" normal-case" v-for="(v,i) in keyList" :key="i" :class="{'group-first:z-0':i==0}">{{v}}
</th>
</tr>
</thead>
<tbody class="">
<tr v-for="(map, i) in tableResults" :key="i">
<th>{{i + 1}}</th>
<template v-for="(key, j) in keyList">
<td class="">
{{map.get(key)}}
</td>
</template>
<div class="card h-full w-2/3 border bg-base-100">
<div class="card-body overflow-auto">
<div class="flex justify-around mb-2">
<h3 class="text-xl">statistics categorized by class type</h3>
<button class="btn btn-primary btn-sm" @click="getCategorizedByClassType">refresh</button>
</div>
<div class="overflow-auto">
<table class="table w-full table-compact">
<thead>
<tr>
<th></th>
<th class=" normal-case" v-for="(v, i) in keyList" :key="i" :class="{ 'group-first:z-0': i == 0 }">
{{ v }}
</th>
</tr>
</thead>
<tbody class="">
<tr v-for="(map, i) in tableResults" :key="i">
<th>{{ i + 1 }}</th>
<template v-for="(key, j) in keyList">
<td class="">
{{ map.get(key) }}
</td>
</template>
</tr>
</tbody>
</table>
</div>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>

@ -8,14 +8,12 @@ import TodoList from '@/components/input/TodoList.vue';
import {
Listbox, ListboxButton, ListboxOptions, ListboxOption
} from '@headlessui/vue';
import { transfromStore } from "@/stores/resTransform"
import permachine from '@/machines/perRequestMachine';
import { watch } from 'fs';
import transformStackTrace from '@/utils/transform';
const fetchS = fetchStore()
const FetchService = useInterpret(permachine)
const stackTrace = reactive([] as string[])
const transformS = transfromStore()
const count = ref(0)
const leastTime = ref(200)
const isBlock = ref(false)
@ -63,15 +61,10 @@ const infoCount = ref({
TERMINATED: 0
} as ThreadStateCount)
const tableResults = reactive([] as Map<string, string>[])
const limitResults = tableResults
// watchEffect(()=>{
// if(count.value > 0) {
// tableResults.length = count.value
// }
// })
const tableFilter = computed(() => {
//
let res = count.value > 0 ? tableResults.filter((v, i)=>i < count.value) : tableResults
let res = count.value > 0 ? tableResults.filter((v, i) => i < count.value) : tableResults
if (includesVal.size === 0) return res;
//
includesVal.forEach((v1) => {
@ -181,7 +174,7 @@ const setleast = publiC.inputDialogFactory(
},
(input) => input.value.toString(),
)
const {increase, decrease} = publiC.numberCondition(count,{min:0})
const { increase, decrease } = publiC.numberCondition(count, { min: 0 })
const getSpecialThreads = (threadid: number = -1) => {
let threadName = threadid > 0 ? `${threadid}` : ""
fetchS.baseSubmit(FetchService, {
@ -191,7 +184,7 @@ const getSpecialThreads = (threadid: number = -1) => {
const result = (res as CommonRes).body.results[0]
if (result.type === "thread") {
stackTrace.length = 0
result.threadInfo.stackTrace.forEach(stack => stackTrace.unshift(transformS.transformStackTrace(stack)))
result.threadInfo.stackTrace.forEach(stack => stackTrace.unshift(transformStackTrace(stack)))
}
})
}
@ -203,10 +196,10 @@ const getSpecialThreads = (threadid: number = -1) => {
<div class="flex justify-end items-center h-[10vh]">
<TodoList title="filter" :val-set="includesVal" class=" mr-2"></TodoList>
<button class="btn ml-2 btn-sm btn-outline" @click="setleast">sample interval:{{leastTime}}</button>
<button class="btn ml-2 btn-sm btn-outline" @click="setleast">sample interval:{{ leastTime }}</button>
<div class="btn-group ml-2" v-show="!isBlock">
<button class="btn btn-outline btn-sm" @click.prevent="decrease">-</button>
<button class="btn btn-outline btn-sm border-x-0" @click.prevent="setlimit">top threads:{{count}}</button>
<button class="btn btn-outline btn-sm border-x-0" @click.prevent="setlimit">top threads:{{ count }}</button>
<button class="btn btn-outline btn-sm" @click.prevent="increase">+</button>
</div>
<Listbox v-model="threadState">
@ -214,10 +207,10 @@ const getSpecialThreads = (threadid: number = -1) => {
<ListboxButton class="btn w-40 btn-sm btn-outline">state {{ threadState.name }}</ListboxButton>
<ListboxOptions
class=" z-10 absolute w-40 mt-2 border overflow-hidden rounded-md hover:shadow-xl transition bg-base-100">
<ListboxOption v-for="(am,i) in statelist" :key="i" :value="am" v-slot="{active, selected}">
<ListboxOption v-for="(am, i) in statelist" :key="i" :value="am" v-slot="{ active, selected }">
<div class=" p-2 transition " :class="{
'bg-neutral text-neutral-content': active,
'bg-neutral-focus text-neutral-content': selected,
'bg-neutral text-neutral-content': active,
'bg-neutral-focus text-neutral-content': selected,
}">
{{ am.name }}
</div>
@ -231,55 +224,58 @@ const getSpecialThreads = (threadid: number = -1) => {
</label>
<button class="btn btn-primary btn-sm btn-outline" @click="getThreads"> get threads </button>
</div>
<div class="w-full h-[50vh] input-btn-style my-2 p-4 flex flex-col">
<div class="flex h-[8vh] flex-wrap flex-auto">
<div v-for="(v, i) in Object.entries(infoCount)" :key="i" class="mr-2">
<span class="text-primary-content border border-primary-focus bg-primary-focus w-44 px-2 rounded-l">
{{ v[0] }}
</span>
<span class="border border-primary-focus bg-base-200 rounded-r flex-1 px-1">
{{v[1]}}
</span>
<div class="w-full h-[50vh] my-2 card rounded-box compact border">
<div class="card-body overflow-auto">
<div class="h-[8vh] flex-wrap flex-auto flex-row flex">
<div v-for="(v, i) in Object.entries(infoCount)" :key="i" class="mr-2">
<span class="text-primary-content border border-primary-focus bg-primary-focus w-44 px-2 rounded-l">
{{ v[0] }}
</span>
<span class="border border-primary-focus bg-base-200 rounded-r flex-1 px-1">
{{ v[1] }}
</span>
</div>
</div>
<div class="overflow-auto h-[40vh] w-full">
<table class="table w-full">
<thead>
<tr>
<th class=""></th>
<template v-if="count === 0">
<th class="normal-case" v-for="(v, i) in keyList" :key="i">{{ v }}</th>
</template>
<template v-else>
<th class="normal-case" v-for="(v, i) in statsList" :key="i">{{ v }}</th>
</template>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableFilter" :key="i">
<th class="2"><button class="btn-outline btn-primary btn btn-sm"
@click="getSpecialThreads(parseInt(map.get('id')!))" v-if="map.get('id') !== '-1'">
get stackTrace
</button></th>
<template v-if="count === 0">
<td class="" v-for="(key, j) in keyList" :key="j">
{{ map.get(key) }}
</td>
</template>
<template v-else>
<td class="" v-for="(key, j) in statsList" :key="j">
{{ map.get(key) }}
</td>
</template>
</tr>
</tbody>
</table>
</div>
</div>
<div class="overflow-auto h-[40vh] w-full">
<table class="table w-full">
<thead>
<tr>
<th class=""></th>
<template v-if="count === 0">
<th class="normal-case" v-for="(v,i) in keyList" :key="i">{{v}}</th>
</template>
<template v-else>
<th class="normal-case" v-for="(v,i) in statsList" :key="i">{{v}}</th>
</template>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableFilter" :key="i">
<th class="2"><button class="btn-outline btn-primary btn btn-sm"
@click="getSpecialThreads(parseInt(map.get('id')!))" v-if="map.get('id')!=='-1'">
get stackTrace
</button></th>
<template v-if="count === 0">
<td class="" v-for="(key,j) in keyList" :key="j">
{{map.get(key)}}
</td>
</template>
<template v-else>
<td class="" v-for="(key,j) in statsList" :key="j">
{{map.get(key)}}
</td>
</template>
</tr>
</tbody>
</table>
</div>
</div>
<div class="input-btn-style flex-auto overflow-auto">
<h2 class="text-lg">stackTrace</h2>
<div v-for="(stack, i) in stackTrace" class="mb-2" :key="i">{{stack}} </div>
<div class=" flex-auto card rounded-box compact border">
<div class="card-body overflow-auto ">
<h2 class="text-lg">stackTrace</h2>
<div v-for="(stack, i) in stackTrace" class="mb-2" :key="i">{{ stack }} </div>
</div>
</div>
</div>
</template>

@ -3,11 +3,13 @@
"private": false,
"version": "0.1.4",
"scripts": {
"dev": "vite --port 8000 --mode ui",
"dev:tunnel": "vite --port 8000 --mode tunnel",
"build": "vue-tsc --noEmit && vite build --mode ui",
"dev:ui": "vite --port 8000 --mode ui",
"build": "vue-tsc --noEmit && vite build --mode tunnel && vite build --mode ui",
"build:tunnel": "vue-tsc --noEmit && vite build --mode tunnel",
"preview": "vite preview"
"build:ui": "vue-tsc --noEmit && vite build --mode ui",
"preview:ui": "vite preview --mode ui",
"preview:tunnel": "vite preview --mode tunnel"
},
"dependencies": {
"@headlessui/vue": "^1.6.6",

@ -1,10 +1,7 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./ui/index.html",
"./index.html",
"./src/*.{vue,js,ts,jsx,tsx}",
"./ui/src/**/*.{vue,js,ts,jsx,tsx}",
"all/**/*.{vue,ts,css}",
],
theme: {
extend: {

@ -14,13 +14,18 @@
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*":["ui/src/*"]
"@/*": ["all/ui/ui/src/*"],
"~/*": ["all/share/*"]
},
"experimentalDecorators": true
},
"include": [
"ui/src/**/*.ts", "ui/src/**/*.d.ts", "ui/src/**/*.tsx", "ui/src/**/*.vue","ui/tests/**/*.ts",
"src/**/*.vue", "src/**/*.ts","src/**/*.d.ts"
"all/**/*.vue",
"all/**/*.ts",
"all/**/*.d.ts",
"all/env.d.ts"
],
"references": [{ "path": "./tsconfig.node.json" }]
"references": [
{ "path": "./tsconfig.node.json" }
]
}

@ -4,5 +4,5 @@
"module": "esnext",
"moduleResolution": "node"
},
"include": ["vite.config.ts"]
"include": ["./vite.config.ts"]
}

@ -1,8 +0,0 @@
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}

@ -1,12 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.button-style {
@apply bg-blue-400 hover:opacity-50 transition rounded-md p-2
}
.input-btn-style {
@apply border p-2 rounded-xl hover:shadow-md transition border-gray-300
}
}

@ -1,9 +0,0 @@
import { defineStore } from "pinia";
export const transfromStore = defineStore("transformStore", {
actions: {
transformStackTrace(trace: StackTrace) {
return `${trace.className}.${trace.methodName} (${trace.fileName}: ${trace.lineNumber})`;
}
},
});

@ -9,28 +9,45 @@ export default defineConfig(({ mode }) => {
`${env.VITE_ARTHAS_PROXY_IP}:${env.VITE_ARTHAS_PROXY_PORT}`;
console.log("Arthas proxy :", proxyTarget);
let outDir, input
console.log(env.VITE_AGENT)
if (env.VITE_AGENT === "true") {
outDir = `./dist/tunnel`
let outDir, input, root, proxy;
if (mode === "tunnel") {
outDir = path.resolve(__dirname, `dist/tunnel`);
root = "./all/tunnel";
input = {
tunnel: path.resolve(__dirname, "index.html")
}
} else {
outDir = `./dist`
tunnel: path.resolve(__dirname, "all/tunnel/index.html"),
apps: path.resolve(__dirname, "all/tunnel/apps.html"),
agents: path.resolve(__dirname, "all/tunnel/agents.html"),
};
proxy = {
"/api": {
target: `http://${proxyTarget}`,
changeOrigin: true,
},
};
} else if (mode === "ui") {
outDir = path.resolve(__dirname, `dist/ui`);
root = "./all/ui";
input = {
main: path.resolve(__dirname, "index.html"),
ui: path.resolve(__dirname, "ui/index.html"),
}
main: path.resolve(__dirname, "all/ui/index.html"),
ui: path.resolve(__dirname, "all/ui/ui/index.html"),
};
proxy = {
"/api": {
target: `http://${proxyTarget}`,
changeOrigin: true,
},
};
}
return {
plugins: [vue({
reactivityTransform: true,
reactivityTransform: path.resolve(__dirname, "all/ui"),
})],
resolve: {
alias: {
"@": path.resolve(__dirname, "./ui/src/"),
"@": path.resolve(__dirname, "all/ui/ui/src"),
"~": path.resolve(__dirname, "all/share"),
},
},
build: {
@ -53,13 +70,10 @@ export default defineConfig(({ mode }) => {
"__VUE_OPTIONS_API__": false,
},
base: "/",
publicDir: path.resolve(__dirname, "all/share/public"),
root,
server: {
proxy: {
"/api": {
target: `http://${proxyTarget}`,
changeOrigin: true,
},
},
proxy,
},
};
});

@ -71,12 +71,21 @@
</configuration>
</execution>
<execution>
<id>vite build</id>
<id>vite build:ui</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>vite build</arguments>
<arguments>vite build --mode ui</arguments>
</configuration>
</execution>
<execution>
<id>vite build:tunnel</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>vite build --mode tunnel</arguments>
</configuration>
</execution>
</executions>

Loading…
Cancel
Save