update web ui (#2318)

* fix(web ui): profiler

* chore(web ui):perf proxy config

* perf(web ui):update style

* chore(web ui):update deps

* perf(web ui):fix monitor category

* fix(web ui):fix style of table and monitor rt chart

* refactor(web ui):refactor config

* feat(web ui):support debug http api with console
pull/2325/head
xudaotutou 2 years ago committed by GitHub
parent f6fe8b9134
commit aa2526075b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,2 @@
# NODE_ENV=production
VITE_AGENT=true

@ -0,0 +1,2 @@
# NODE_ENV=production
VITE_AGENT=false

@ -3,8 +3,10 @@
"private": false,
"version": "0.1.4",
"scripts": {
"dev": "vite --port 8000",
"build": "vue-tsc --noEmit && vite build",
"dev": "vite --port 8000 --mode ui",
"dev:tunnel": "vite --port 8000 --mode tunnel",
"build": "vue-tsc --noEmit && vite build --mode ui",
"build:tunnel": "vue-tsc --noEmit && vite build --mode tunnel",
"preview": "vite preview"
},
"dependencies": {
@ -31,6 +33,6 @@
"tailwindcss": "^3.1.4",
"typescript": "^4.7.4",
"vite": "^2.9.9",
"vue-tsc": "^0.34.7"
"vue-tsc": "1.0.8"
}
}

@ -2,7 +2,7 @@
import { onMounted, ref } from "vue";
import { Terminal } from "xterm"
import { FitAddon } from 'xterm-addon-fit';
import {WebglAddon} from "xterm-addon-webgl"
import { WebglAddon } from "xterm-addon-webgl"
let ws: WebSocket | undefined;
@ -14,9 +14,11 @@ 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 fitAddon = new FitAddon();
const webglAddon = new WebglAddon();
let xterm = new Terminal({allowProposedApi: true})
let xterm = new Terminal({ allowProposedApi: true })
onMounted(() => {
ip.value = getUrlParam('ip') ?? window.location.hostname;
@ -27,7 +29,7 @@ onMounted(() => {
startConnect(true);
window.addEventListener('resize', function () {
if (ws !== undefined && ws !== null) {
const {cols, rows} = fitAddon.proposeDimensions()!
const { cols, rows } = fitAddon.proposeDimensions()!
ws.send(JSON.stringify({ action: 'resize', cols, rows: rows }));
fitAddon.fit();
}
@ -56,7 +58,7 @@ function initWs(silent: boolean) {
let scrollback = getUrlParam('scrollback') ?? '0';
const {cols, rows} = initXterm(scrollback)
const { cols, rows } = initXterm(scrollback)
xterm.onData(function (data) {
ws?.send(JSON.stringify({ action: 'read', data: data }))
});
@ -85,7 +87,7 @@ function initXterm(scrollback: string) {
scrollback: isValidNumber(scrollNumber) ? scrollNumber : DEFAULT_SCROLL_BACK
});
xterm.loadAddon(fitAddon)
xterm.open(document.getElementById('terminal')!);
xterm.loadAddon(webglAddon)
@ -136,8 +138,8 @@ function disconnect() {
function xtermFullScreen() {
var ele = document.getElementById('terminal-card')!;
requestFullScreen(ele);
ele.onfullscreenchange = (e:Event)=>{
fitAddon.fit()
ele.onfullscreenchange = (e: Event) => {
fitAddon.fit()
}
}
@ -162,8 +164,8 @@ function requestFullScreen(element: HTMLElement) {
<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>
<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">
<li>
<a class="hover:text-sky-500 dark:hover:text-sky-400 text-sm" href="https://arthas.aliyun.com/doc"
@ -200,7 +202,7 @@ function requestFullScreen(element: HTMLElement) {
<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 class="btn btn-sm bg-secondary hover:bg-secondary-focus border-none text-secondary-content focus:bg-secondary-focus normal-case"
<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>
</div>
</form>

@ -4,4 +4,11 @@ declare module '*.vue' {
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
}
interface ImportMetaEnv {
readonly VITE_AGENT:string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}

@ -1,11 +1,9 @@
<script setup lang="ts">
import NavAside from "@/components/routeTo/NavAside.vue";
<script setup lang="ts">
// import NavAside from "@/components/routeTo/NavAside.vue";
import NavHeader from "@/components/NavHeader.vue";
import ErrDialog from "@/components/dialog/ErrDialog.vue";
import SuccessDialog from "@/components/dialog/SuccessDialog.vue";
import { onBeforeUnmount } from "vue";
import machine from "./machines/consoleMachine";
import { interpret } from "xstate";
import { fetchStore } from "./stores/fetch";
import InputDialog from "./components/dialog/InputDialog.vue";
import { publicStore } from "./stores/public";
@ -13,24 +11,16 @@ import WarnDialog from "./components/dialog/WarnDialog.vue";
const fetchS = fetchStore()
const publicS = publicStore()
onBeforeUnmount(() => {
const actor = interpret(machine)
actor.start()
actor.send("INIT")
actor.send({
type: "SUBMIT",
value: {
action: "interrupt_job",
} as AsyncReq
})
fetchS.interruptJob()
})
</script>
<!-- dialog用v-if方便触发hooks -->
<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>
<!-- <nav-aside ></nav-aside> -->
<div class="flex-auto overflow-auto h-[90vh] w-[90vw]">
<router-view>
</router-view>

@ -1,4 +1,3 @@
type SessionAction =
| "join_session"
| "init_session"
@ -68,7 +67,7 @@ type AsyncReq = SessionId<
} | {
command: StringInclude<"stack", 3>;
} | {
command: `monitor -c ${number} ${string} ${string}`;
command: `monitor ${string} ${string} ${string} ${string}`;
} | {
command: `trace ${string} ${string}`;
} | {
@ -88,6 +87,7 @@ type CommandReq = CommonAction<
| "sysenv"
| "version"
| "sysprop"
| `sysprop ${string} ${string}`
| "pwd"
| "jvm"
| "memory"
@ -114,6 +114,8 @@ type CommandReq = CommonAction<
| `profiler ${"list" | "status" | "stop" | "resume" | "getSamples"}`
| `profiler ${string}`
| `stop`
| `options`
| `options ${string} ${string}`
| `ognl ${string}`;
} | {
command: StringInclude<"vmoption" | "thread", 2>;
@ -362,6 +364,12 @@ type TimeFragment = {
"throwExp": string;
"timestamp": string;
};
type Perfcounter = {
name: string;
units: string;
value: string | number;
variability: string;
};
type MonitorData = {
className: string;
cost: number;
@ -369,6 +377,15 @@ type MonitorData = {
methodName: number;
success: number;
total: number;
timestamp: string;
};
type GlobalOptions = {
"description": string;
"level": number;
"name": string;
"summary": string;
"type": string;
"value": string;
};
type CommandResult = {
type: "command";
@ -402,6 +419,14 @@ type CommandResult = {
threadStats: never;
busyThreads: never;
type: "thread";
} | {
options: GlobalOptions[];
changeResult: {
"afterValue": unknown,
"beforeValue": unknown,
"name": string
};
type: "options";
} | {
all: boolean;
threadStateCount: never;
@ -416,43 +441,23 @@ type CommandResult = {
memoryInfo: MemoryInfo;
type: "memory";
} | {
perfCounters: {
name: string;
units: string;
value: string | number;
variability: string;
}[];
perfCounters: Perfcounter[];
type: "perfcounter";
} | {
"classLoaderStats": Record<string,Record<"loadedCount"|"numberOfInstance",number>>
urlStats: never;
urls:never;
tree:never;
type: "classloader";
} | {
type: "classloader";
"classLoaderStats": Record<
string,
Record<"loadedCount" | "numberOfInstance", number>
>;
urlStats: {
[x: `{hash":${string},"name:${string}}`]: {
unUsedUrls: string[];
usedUrls: string[];
};
};
"classLoaderStats":never;
urls: never;
tree: never;
} | {
type: "classloader";
urls: never;
"classLoaderStats";
urlStats:never;
urls: string[];
classLoaders: ClassLoaderNode[];
tree: boolean;
} | {
type: "classloader";
urls: string[];
urlStats:never;
"classLoaderStats":never;
tree: never;
} | {
classInfo: ClassInfo;
detailed: true;

@ -1,12 +1,14 @@
<script setup lang="ts">
import { useMachine } from '@xstate/vue';
import { onBeforeMount, Ref, ref, watchEffect } from 'vue';
import { computed, onBeforeMount, Ref, ref, watchEffect } from 'vue';
import { RefreshIcon, LogoutIcon, LoginIcon, MenuIcon, XCircleIcon } from '@heroicons/vue/outline';
import { fetchStore } from '@/stores/fetch';
import machine from "@/machines/consoleMachine"
import { publicStore } from '@/stores/public';
import { interpret } from 'xstate';
import { Menu, MenuButton, MenuItems, MenuItem } from '@headlessui/vue'
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';
const fetchM = useMachine(machine)
const publicS = publicStore()
@ -22,8 +24,9 @@ const vCmd: CommandReq = {
const restBtnclass: Ref<'animate-spin-rev-pause' | 'animate-spin-rev-running'> = ref('animate-spin-rev-pause')
publicS.getCommonResEffect(fetchM, body => {
const result = body.results[0]
if (result.type === "version") version.value = result.version
})
if (result.type === "version") {
version.value = result.version
}})
watchEffect(() => {
if (!fetchS.wait) restBtnclass.value = "animate-spin-rev-pause"
@ -36,6 +39,7 @@ onBeforeMount(() => {
value: vCmd
})
sessionM.send("INIT")
// fetchS.baseSubmit()
})
//
const reset = () => {
@ -72,7 +76,6 @@ const logout = async () => {
})
restBtnclass.value = "animate-spin-rev-pause"
}
const login = async () => {
sessionM.send("SUBMIT", {
value: {
@ -99,59 +102,103 @@ const resetAllClass = () => {
}).then(response => {
const result = (response as CommonRes).body.results[0]
if (result.type === "reset") {
publicS.isSuccess=true
publicS.SuccessMessage = JSON.stringify(result.affect)
publicS.isSuccess = true
publicS.SuccessMessage = JSON.stringify(result.affect)
}
})
}
const tools:[string,()=>void][] = [
const tabs = [
{
name: 'dashboard',
url: "/dashboard",
icon: DesktopComputerIcon
},
{
name: 'immediacy',
url: '/synchronize',
icon: ViewGridIcon
}, {
name: "real time",
url: '/asynchronize',
icon: ViewGridIcon
},
{
name: 'option',
url: '/config',
icon: PuzzleIcon
},
{
name: 'console',
url: '/console',
icon: TerminalIcon
},
{
name:'terminal',
url:'terminal',
icon:TerminalIcon
}
]
const tools: [string, () => void][] = [
["forceGc", forceGc],
["shutdown", shutdown],
["reset class", resetAllClass]
]
const router = useRouter()
const routePath = computed(() => useRoute().path)
const toNext = (url: string) => {
if(url === "terminal") {
window.open("/","_blank")
} else router.push(url)
}
</script>
<template>
<nav class=" h-[10vh] flex justify-between items-center min-h-max border-b-2 shadow-orange-300">
<a class="w-40 flex items-center justify-center" href="https://arthas.aliyun.com/doc/commands.html" target="_blank">
<img src="/arthas.png" alt="logo" class=" w-3/4" />
</a>
<div class="flex items-center h-20">
<div class=" mr-4 bg-info text-info-content h-12 rounded-full flex justify-center items-center font-bold p-2">
sessionId: {{fetchS.sessionId}}</div>
<div class=" mr-4 bg-info text-info-content h-12 p-2 rounded-full flex justify-center items-center font-bold">
version:{{ version }}
</div>
<nav class=" h-[10vh] border-b-2 navbar">
<div class=" navbar-start flex items-stretch ">
<!-- <div class=" indicator mx-3"> -->
<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" />
</a>
<span class="badge badge-ghost self-end text-sm">v{{version}}</span>
<!-- </div> -->
</div>
<div class="navbar-center">
<ul class="menu menu-horizontal p-0">
<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), }">
<component :is="tab.icon" class="w-4 h-4" />
{{
tab.name
}}
</a>
</li>
</ul>
</div>
<div class="flex items-center h-20 navbar-end">
<button v-if="fetchS.jobRunning" @click.prevent="interruptEvent"
class="btn-error btn rounded-full h-1/2 p-2 transition mr-4">interrupt</button>
<button class=" rounded-full btn btn-info btn-circle h-12 w-12 flex justify-center items-center mr-4 " @click="reset">
<refresh-icon class="h-3/4 w-3/4" :class="restBtnclass" />
class="btn-error btn h-1/2 p-2">interrupt</button>
<div class="dropdown dropdown-end mr-2">
<label tabindex="0" class="btn btn-ghost m-1">
<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>
</ul>
</div>
<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="hover:opacity-50 h-12 w-12 grid place-items-center rounded-full mr-2 transition-all"
:class="{ 'bg-primary': !fetchS.online, 'bg-error': fetchS.online }">
<LogoutIcon class="h-1/2 w-1/2 text-error-content" @click="logout" v-if="fetchS.online" />
<login-icon class="h-1/2 w-1/2 text-primary-content" @click="login" v-else />
<button class="btn-ghost btn"
@click="reset">
<refresh-icon class="h-6 w-6" :class="restBtnclass" />
</button>
<Menu as="div" class="relative mr-4">
<MenuButton
class="w-12 h-12 input-btn-style grid place-items-center rounded-full bg-primary transition">
<MenuIcon class="h-3/4 w-3/4 text-primary-content"></MenuIcon>
<!-- <XCirleIcon class="h-3/4 w-3/4"></XCirleIcon> -->
</MenuButton>
<MenuItems class="absolute right-0 top-full input-btn-style mt-4 bg-white px-0 z-10 w-40">
<MenuItem v-slot="{ active }" v-for="(v,i) in tools" :key="i">
<div :class='{ "bg-blue-500 text-primary-content": active }' class="px-4 py-2">
<button @click.prevent="v[1]">{{v[0]}}</button>
</div>
</MenuItem>
</MenuItems>
</Menu>
</div>
</nav>
</template>
<style scoped>
</style>
</template>

@ -24,9 +24,9 @@ onBeforeMount(()=>{fetchStore().curPolling.close()})
<Dialog @close="setIsOpen" class="min-w-max z-20">
<TransitionChild enter="transition-opacity duration-300" enter-from="opacity-0" enter-to="opacity-100"
leave="transition-opacity duration-300" leave-from="opacity-100" leave-to="opacity-0">
<div class="fixed inset-0 bg-black bg-opacity-25" />
<div class="fixed inset-0 bg-black bg-opacity-25 z-20" />
</TransitionChild>
<div class="fixed inset-0 grid place-items-center min-w-max">
<div class="fixed inset-0 grid place-items-center min-w-max z-30">
<TransitionChild as="template" enter="duration-300 ease-out" enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100" leave="duration-200 ease-in" leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95">

@ -8,9 +8,8 @@ import {
TransitionChild,
TransitionRoot
} from '@headlessui/vue'
import { onMounted, ref, onBeforeMount } from 'vue';
import { onMounted, ref } from 'vue';
const store = publicStore()
const debug = (e: any) => console.log(e)
const inputV = ref("")
onMounted(() => {
@ -20,10 +19,11 @@ onMounted(() => {
function setIsOpen() {
store.inputVal = inputV.value
console.log(store.inputVal, inputV.value)
store.inputE = true
store.isInput = false
}
function setIsOpenCancel() {
store.inputE = false
store.isInput = false
}
</script>
@ -33,9 +33,9 @@ function setIsOpenCancel() {
<Dialog @close="setIsOpenCancel" class="min-w-max z-20">
<TransitionChild enter="transition-opacity duration-300" enter-from="opacity-0" enter-to="opacity-100"
leave="transition-opacity duration-300" leave-from="opacity-100" leave-to="opacity-0">
<div class="fixed inset-0 bg-black bg-opacity-25" />
<div class="fixed inset-0 bg-black bg-opacity-25 z-20" />
</TransitionChild>
<div class="fixed inset-0 grid place-items-center min-w-max">
<div class="fixed inset-0 grid place-items-center min-w-max z-30">
<TransitionChild as="template" enter="duration-300 ease-out" enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100" leave="duration-200 ease-in" leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95">

@ -22,9 +22,9 @@ function setIsOpen(value: boolean) {
<Dialog @close="setIsOpen" class="min-w-max z-20">
<TransitionChild enter="transition-opacity duration-300" enter-from="opacity-0" enter-to="opacity-100"
leave="transition-opacity duration-300" leave-from="opacity-100" leave-to="opacity-0">
<div class="fixed inset-0 bg-black bg-opacity-25" />
<div class="fixed inset-0 bg-black bg-opacity-25 z-20" />
</TransitionChild>
<div class="fixed inset-0 grid place-items-center min-w-max">
<div class="fixed inset-0 grid place-items-center min-w-max z-30">
<TransitionChild as="template" enter="duration-300 ease-out" enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100" leave="duration-200 ease-in" leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95">

@ -29,9 +29,9 @@
<Dialog @close="setIsOpenCancel" class="min-w-max min-h-max z-20">
<TransitionChild enter="transition-opacity duration-300" enter-from="opacity-0" enter-to="opacity-100"
leave="transition-opacity duration-300" leave-from="opacity-100" leave-to="opacity-0">
<div class="fixed inset-0 bg-black bg-opacity-25" />
<div class="fixed inset-0 bg-black bg-opacity-25 z-20" />
</TransitionChild>
<div class="fixed inset-0 grid place-items-center min-w-max">
<div class="fixed inset-0 grid place-items-center min-w-max z-30">
<TransitionChild as="template" enter="duration-300 ease-out" enter-from="opacity-0 scale-95"
enter-to="opacity-100 scale-100" leave="duration-200 ease-in" leave-from="opacity-100 scale-100"
leave-to="opacity-0 scale-95">

@ -91,7 +91,7 @@ const blurF = (event:Event)=>{
'bg-blue-600 text-white': selected,
'text-gray-900': !active && !selected,
}">
<span class="block truncate"
<span class="block"
:class="{ 'font-medium': selected, 'font-normal': !selected, 'text-white': active, 'text-teal-600': !active && !selected }">
{{ item.name }}
</span>

@ -84,7 +84,7 @@ const setExpress = publicStore().inputDialogFactory(
raw => raw,
_ => _.value
)
const { increase, decrease } = publicStore().numberCondition(autoStop, { min: 0, max: 100 })
const filterfn = (_: any, item: Item) => true
</script>
@ -95,9 +95,16 @@ const filterfn = (_: any, item: Item) => true
<AutoComplete label="method" :option-items="optionMethod"
:input-fn="(value: string) => changeMethod(slotClass.selectItem.value as string, value)" :filter-fn="filterfn"
v-slot="slotMethod">
<button v-if="nexpress" class="btn btn-sm btn-outline ml-2" @click="setExpress">express:{{express}}</button>
<button v-if="ncondition" class="btn btn-sm btn-outline ml-2" @click="setConditon">condition:{{conditon}}</button>
<button v-if="ncount" class="btn btn-sm btn-outline ml-2" @click="setCount">count:{{autoStop}}</button>
<button v-if="nexpress" class="btn btn-sm btn-outline ml-2"
@click.prevent="setExpress">express: <span class="normal-case">{{express}}</span></button>
<button v-if="ncondition" class="btn btn-sm btn-outline ml-2"
@click.prevent="setConditon">condition: <span class="normal-case">{{conditon}}</span></button>
<div class="btn-group ml-2" v-if="ncount">
<button class="btn btn-sm btn-outline" @click.prevent="decrease">-</button>
<button class="btn btn-sm btn-outline border-x-0" @click.prevent="setCount">count:{{autoStop}}</button>
<button class="btn btn-sm btn-outline" @click.prevent="increase">+</button>
</div>
<slot name="others" :methodItem="slotMethod.selectItem" :classItem="slotClass.selectItem"></slot>
<button @click.prevent="submitF({
classItem: slotClass.selectItem,

@ -1,57 +0,0 @@
<script setup lang="ts">
import { computed, reactive, ref } from 'vue';
import { PuzzleIcon, TerminalIcon, ViewGridIcon } from "@heroicons/vue/outline"
import { DesktopComputerIcon } from "@heroicons/vue/solid"
import { useRoute, useRouter } from 'vue-router';
const tabs = [
{
name: 'dashboard',
url: "/dashboard",
icon: DesktopComputerIcon
},
{
name: 'immediacy',
url: '/synchronize',
icon: ViewGridIcon
}, {
name: "real time",
url: '/asynchronize',
icon: ViewGridIcon
},
{
name: 'option',
url: '/config',
icon: PuzzleIcon
},
// {
// name: 'console',
// url: '/console',
// icon: TerminalIcon
// },
]
const router = useRouter()
const routePath = computed(() => useRoute().path)
const toNext = (url: string) => {
router.push(url)
}
const a: StatusResult = { type: "status", message: "", statusCode: 0 }
</script>
<template>
<ul class="menu bg-base-200 w-[10vw] menu-compact">
<li v-for="(tab, idx) in tabs" :key="idx"
@click="toNext(tab.url)" class="pl-2" >
<a class="break-all" :class="{ 'bg-primary text-primary-content': routePath.includes(tab.url), }">
<component :is="tab.icon" class="w-4 h-4" />
{{
tab.name
}}
</a>
</li>
</ul>
</template>
<style scoped>
</style>

@ -11,7 +11,7 @@ const routePath = computed(() => route.path)
</script>
<template>
<ul class=" w-[10vw] menu bg-base-300 menu-compact">
<ul class=" w-[10vw] menu bg-base-200 menu-compact">
<li v-for="(v, i) in routes" :key="i">
<a @click="() => router.push(v.url)" :class='{"bg-secondary text-secondary-content":routePath.includes(v.url)}'>
{{ v.cmd }}

@ -19,7 +19,9 @@ if (result.type === "enhancer") {
<div class="stat-title">{{kv[0]}}</div>
<div class="stat-value">{{kv[1]}}</div>
</div>
<slot name="otherStat">
</slot>
</div>
</template>

@ -406,8 +406,19 @@ const machine =
result.message ===
"all consumers are unhealthy, current job was interrupted."
) {
return false;
}
if (
result.type === "options" &&
Object.hasOwn(result, "changeResult") &&
result.changeResult.afterValue === result.changeResult.beforeValue &&
(result.changeResult.afterValue as string).toString() !== (context.inputValue as CommandReq).command.split(" ")[2]
) {
console.log("?????")
// arthas 本身不会对 options抛错得手动抛错
return false
}
return true;
});
} else {

@ -276,8 +276,8 @@ const permachine = createMachine({
isErr: true,
ErrMessage: context.err,
});
} else{
console.error(context.err)
} else {
console.error(context.err);
}
return {
err: "",
@ -302,14 +302,13 @@ const permachine = createMachine({
};
}),
needReportSuccess: (context, e) => {
if (context.inputValue?.action === "close_session") {
context.fetchStore.$patch({
sessionId: "",
consumerId: "",
online: false,
});
if(context.publicStore.ignore) return;
if (context.publicStore.ignore) return;
context.publicStore.$patch({
isSuccess: true,
SuccessMessage: `close session success!`,
@ -323,7 +322,7 @@ const permachine = createMachine({
consumerId: response.consumerId,
online: true,
});
if(context.publicStore.ignore) return;
if (context.publicStore.ignore) return;
context.publicStore.$patch({
isSuccess: true,
SuccessMessage: `init_session success!`,
@ -391,7 +390,27 @@ const permachine = createMachine({
if (Object.hasOwn(event.data, "body")) {
if (Object.hasOwn(event.data.body, "results")) {
return (event.data as CommonRes).body.results.every((result) => {
return result.type === "status" ? result.statusCode === 0 : true;
if (result.type === "status" && result.statusCode !== 0) {
return false;
}
if (
result.type === "message" &&
result.message ===
"all consumers are unhealthy, current job was interrupted."
) {
return false;
}
if (
result.type === "options" &&
Object.hasOwn(result, "changeResult") &&
(result.changeResult.afterValue as string).toString() !==
(context.inputValue as CommandReq).command.split(" ")[2]
) {
// console.warn("?????");
// arthas 本身不会对 options抛错得手动抛错
return false;
}
return true;
});
} else {
return ["READY", "TERMINATED"].includes(

@ -8,11 +8,31 @@ const routes: RouteRecordRaw[] = [
{
path: "/config",
component: () => import("@/views/Config.vue"),
children:[
{
path:"",
redirect:"/config/perCounter"
}, {
path: "perCounter",
component:()=>import("@/views/config/PerCounter.vue")
},{
path:"sysenv",
component:()=>import("@/views/config/Sysenv.vue")
},{
path:"sysprop",
component:()=>import("@/views/config/Sysprop.vue")
},{
path:"jvm",
component:()=>import("@/views/config/Jvm.vue")
},{
path:"vmoption",
component:()=>import("@/views/config/Vmoption.vue")
},{
path:"options",
component:()=>import("@/views/config/Options.vue")
}
]
},
// {
// path: "/console",
// component: () => import("@/views/Console.vue"),
// },
{
path: "/dashboard",
component: () => import("@/views/DashBoard.vue"),
@ -29,18 +49,15 @@ const routes: RouteRecordRaw[] = [
path: "thread",
component: () => import("@/views/sync/Thread.vue"),
},
// {
// path: "memory",
// component: () => import("@/views/sync/Memory.vue"),
// },
{
path: "jad",
component: () => import("@/views/sync/Jad.vue"),
},
{
path: "retransform",
component: () => import("@/views/sync/Retransform.vue"),
},
// {
// path: "retransform",
// component: () => import("@/views/sync/Retransform.vue"),
// },
{
path: "mbean",
component: () => import("@/views/sync/Mbean.vue"),
@ -110,6 +127,9 @@ const routes: RouteRecordRaw[] = [
component: ()=>import("@/views/async/Profiler.vue")
}
],
},
},{
path:"/console",
component:()=>import("@/views/Console.vue")
}
];
export default routes;

@ -51,6 +51,8 @@ export const fetchStore = defineStore("fetch", {
jobIdSet: new Set<string>(),
//由于轮询只会轮询一个命令,可以直接挂载当前的轮询机
curPolling: nullLoop,
//获取osName 通过dashboard
osName:""
}),
getters: {
getRequest: (state) =>

@ -23,6 +23,10 @@ export const publicStore = defineStore("public", { // Public项目唯一id
*/
isInput: false,
inputVal: "",
/**
* inputEtruefalse
*/
inputE: false,
ErrMessage: "bug!!!",
isSuccess: false,
SuccessMessage: "bug!!!",
@ -59,10 +63,9 @@ export const publicStore = defineStore("public", { // Public项目唯一id
});
},
/**
*
* @param inputRef
* @param getVal inputRef
* @param setVal inputRef
* @param getVal inputRef
* @param setVal inputRef
* @returns
*/
inputDialogFactory<T = string>(
@ -75,14 +78,18 @@ export const publicStore = defineStore("public", { // Public项目唯一id
// 发布订阅模式把函数的闭包里的mutex和缓冲区的锁注册到vue上
watchEffect(() => {
if (mutex.value && !this.isInput) {
//先上锁,防止再次触发该副作用
//先上锁,防止再次触发该副作用
mutex.value = false;
// 把缓冲区的值输入到需要使用的组件里
inputRef.value = getVal(this.inputVal);
// 触发确认输入事件再输入
if(this.inputE) inputRef.value = getVal(this.inputVal);
// reset
this.inputE = false;
// 清空缓冲区
this.inputVal = "";
}
});
return () => {
this.$patch({
// 打开缓冲区
@ -94,6 +101,19 @@ export const publicStore = defineStore("public", { // Public项目唯一id
mutex.value = true;
};
},
numberCondition(
raw: Ref<number>,
scope: { min?: number; max?: number },
) {
return {
increase() {
(scope.max === undefined || raw.value < scope.max) && raw.value++;
},
decrease() {
(scope.min === undefined || raw.value > scope.min) && raw.value--;
},
};
},
nanoToMillis(nanoSeconds: number): number {
return nanoSeconds / 1000000;
},

@ -1,168 +1,35 @@
<script setup lang="ts">
import machine from '@/machines/consoleMachine';
import { useInterpret, useMachine } from '@xstate/vue';
import { onBeforeMount, reactive, ref, watchEffect } from 'vue';
import OptionConfigMenu from '@/components/show/OptionConfigMenu.vue';
import SwitchInput from '@/components/input/SwitchInput.vue';
import { publicStore } from '@/stores/public';
import CmdResMenu from '@/components/show/CmdResMenu.vue';
import { fetchStore } from '@/stores/fetch';
import permachine from '@/machines/perRequestMachine';
const fetchS = fetchStore()
const sysEnvMap = reactive(new Map<string, string[]>())
const sysPropMap = reactive(new Map<string, string[]>())
const perfcounterMap = reactive(new Map<string, string[]>())
const vmOptionM = useMachine(machine)
const pwd = ref("?")
const vmOptionMTree = reactive([] as VmOption[])
import SelectCmd from '@/components/routeTo/SelectCmd.vue';
//
onBeforeMount(() => {
fetchS.baseSubmit(useInterpret(permachine), {
action: "exec",
command: "pwd"
}).then(
res => {
const result = (res as CommonRes).body.results[0]
if (result.type == "pwd") {
pwd.value = result.workingDir
}
}
)
vmOptionM.send("INIT")
vmOptionM.send({
type: "SUBMIT",
value: {
action: "exec",
command: "vmoption"
}
})
})
//
const handleTree = (data: Record<string, string | boolean | number>, map: Map<string, string[]>): string[] => {
map.clear()
let res: string[] = []
Object.entries(data).forEach(([k, v]) => {
res.push(k)
if (typeof v === "boolean") v = v.toString()
if (typeof v === "number") v = v.toString()
if (k.toLowerCase().includes("path")) {
map.set(k, v.split(":").filter(v => v.trim() !== ''))
} else if (v.includes(";")) {
map.set(k, v.split(";").filter(v => v.trim() !== ''))
} else {
map.set(k, [v])
}
})
return res
}
const handleEnvTree = (data: Record<string, string>) => handleTree(data, sysEnvMap)
const handlePropTree = (data: Record<string, string>) => handleTree(data, sysPropMap)
watchEffect(() => {
const response = vmOptionM.state.value.context.response
if (response) {
if (Object.hasOwn(response, "body")) {
console.log(response, "vmoption")
const result = (response as CommonRes).body.results[0]
if (result.type == "vmoption") {
// clear西
vmOptionMTree.length = 0
console.log(result.vmOptions, "watchEffect!!!")
result.vmOptions.forEach(v => {
vmOptionMTree.push(v)
})
}
}
}
})
const vmOptionSend = (pre: string) => (v: { key: string, value: boolean | string }) => {
if (pre === "HeapDumpPath" && v.value === "") {
publicStore().$patch({ ErrMessage: "HeapDumpPath can't be set \"\" ", isErr: true })
return
} vmOptionM.send({
type: 'SUBMIT', value: {
action: "exec",
command: `vmoption ${pre} ${v.value === "" ? '\"\"' : v.value}`
}
})
}
const jvmMap = reactive(new Map<string, string[]>())
const getJvm = () => fetchS.baseSubmit(useInterpret(permachine), {
action: "exec",
command: "jvm"
}).then(res => {
const result = (res as CommonRes).body.results[0]
if (result.type === "jvm") {
jvmMap.clear()
Object.entries(result.jvmInfo).forEach(([k, v]) => {
jvmMap.set(k, v.map(v => `${v.name} : ${v.value}`))
})
}
})
const getSysenv = () => fetchS.baseSubmit(useInterpret(permachine), {
action: "exec",
command: "sysenv",
}).then(res => {
let result = (res as CommonRes).body.results[0]
if (result.type == "sysenv") {
handleEnvTree(result.env)
}
})
const getSysprop = () => fetchS.baseSubmit(useInterpret(permachine), {
action: "exec",
command: "sysprop",
}).then(res => {
let result = (res as CommonRes).body.results[0]
if (result.type == "sysprop") {
handlePropTree(result.props)
}
})
const getPerCounter = () => fetchS.baseSubmit(useInterpret(permachine), { action: "exec", command: "perfcounter -d" }).then(res => {
const result = (res as CommonRes).body.results[0]
if (result.type === "perfcounter") {
const perfcounters = result.perfCounters
perfcounterMap.clear()
perfcounters.forEach(v => {
perfcounterMap.set(v.name, Object.entries(v).filter(v => v[0] !== "name").map(([key, value]) => `${key} : ${value}`))
})
const routes: { cmd: string, url: string }[] = [
{
cmd: "JVM",
url: "jvm"
},{
cmd:"system property",
url:"sysprop"
},{
cmd:"system environment variables",
url:"sysenv"
},{
cmd:"JVM Perf Counter information",
url:"PerCounter"
},{
cmd:"JVM diagnostic options",
url:"vmoption"
},{
cmd:"global options",
url:"options"
}
})
]
</script>
<template>
<div class="p-2 h-[90vh] overflow-y-scroll">
<article>
<div class="flex items-center">
<div class="btn-info btn my-2 btn-sm normal-case">workingDir</div>
<div class="bg-base-200 w-full text-base-content pl-2"> {{ pwd }}</div>
</div>
<CmdResMenu title="sysenv" :map="sysEnvMap" @click="getSysenv" />
<CmdResMenu title="sysprop" :map="sysPropMap" @click="getSysprop" />
<option-config-menu title="vmOption" :list="vmOptionMTree" title-key-name="name">
<template #item="{ kv, itemTitle, idx }">
<switch-input :send="vmOptionSend(itemTitle)" :data="{ key: kv[0], value: kv[1] }" v-if="kv[0] === 'value'"
:class="{ 'border-t-4': (idx > 0), 'border-base-100': (idx > 0) }">
</switch-input>
<div v-else class="flex " :class="{ 'border-t-4': (idx > 0), 'border-base-100': (idx > 0) }">
<div class="bg-blue-200 w-1/5 p-1">{{ kv[0] }}</div>
<div class="grid place-items-center w-3/5">{{ kv[1] }}</div>
</div>
</template>
</option-config-menu>
<CmdResMenu title="jvm" :map="jvmMap" class="w-full" @click="getJvm" />
<CmdResMenu title="perfcounter" :map="perfcounterMap" @click="getPerCounter" />
</article>
<div class="h-[90vh] overflow-auto flex">
<SelectCmd :routes="routes"></SelectCmd>
<div class="overflow-auto py-2 w-full flex flex-col flex-1 pointer-events-auto">
<RouterView></RouterView>
</div>
</div>
</template>

@ -15,14 +15,12 @@ onBeforeMount(()=>{
})
const submitCommand = ()=>{
console.log('别报错了')
fetchM.send({ type: 'SUBMIT', value: val.value})
}
</script>
<template>
<div class="flex flex-col p-2">
<div class="flex flex-col ">
<form class="h-[10vh] flex items-center border shadow" @submit.prevent="submitCommand">
<label for="command-input" class=" m-2 ">command:</label>
<div class=" flex-auto grid place-items-start">
@ -47,4 +45,4 @@ const submitCommand = ()=>{
</template>
<style scoped>
</style>·
</style>

@ -181,6 +181,7 @@ const setPri = publiC.inputDialogFactory(
},
(input) => input.value.toString(),
)
const { increase, decrease } = publiC.numberCondition(pri, { min: 1 })
const transformRuntimeInfo = (result: ArthasResResult) => {
if (result.type !== "dashboard") return;
for (const key in result.runtimeInfo as RuntimeInfo) {
@ -457,23 +458,30 @@ onBeforeUnmount(async () => {
<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>
<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 overflow-auto flex-1 h-80">
<div class="input-btn-style flex-1 h-80 overflow-auto w-0">
<div class="flex justify-end mb-2">
<button class="btn btn-sm btn-outline" @click="setPri">limit:{{pri}}</button>
<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 group">
<table class="table table-compact w-full">
<thead>
<tr>
<th class="border-slate-300" v-for="(v,i) in keyList" :key="i" :class="{'group-first:z-0':i==0}">{{v}}</th>
<th></th>
<th v-for="(v,i) in keyList" :key="i" class="normal-case">{{v}}
</th>
</tr>
</thead>
<tbody class="">
<tr v-for="(map, i) in tableResults" :key="i">
<td class="border border-slate-300" v-for="(key,j) in keyList" :key="j">
<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>

@ -16,9 +16,9 @@ const routes: { cmd: string, url: string }[] = [
}, {
cmd: "jad",
url: "jad"
}, {
cmd: "retransform",
url: "retransform"
// }, {
// cmd: "retransform",
// url: "retransform"
}, {
cmd: "mbean",
url: "mbean"

@ -40,7 +40,7 @@ import {
import {
SVGRenderer
} from 'echarts/renderers';
import { ECharts} from 'echarts/core';
import { ECharts } from 'echarts/core';
echarts.use(
[TitleComponent, ToolboxComponent, TooltipComponent, GridComponent, LegendComponent, DataZoomComponent, BarChart, LineChart, SVGRenderer, UniversalTransition]
@ -63,12 +63,16 @@ const modelist: { name: string, value: string }[] = [
]
const mode = ref(modelist[1])
const averageRT = ref({
totalCost: 0,
totalCount: 0,
})
const chartContext: {
count: number,
myChart?: ECharts,
costChart?: ECharts,
categories: number[],
categories: string[],
data: number[],
cur: number,
max: number,
@ -85,7 +89,7 @@ const chartContext: {
successData: [],
failureData: [],
}
for (let i = 0; i < chartContext.count; i++) { chartContext.categories[i] = i + 1 }
// for (let i = 0; i < chartContext.count; i++) { chartContext.categories[i] = i + 1 }
const chartOption = {
tooltip: {
@ -107,8 +111,12 @@ const chartOption = {
xAxis: [
{
type: 'category',
boundaryGap: true,
data: chartContext.categories
data: chartContext.categories,
axisLabel: {
formatter(value: string) {
return value.split(" ")[1]
}
}
}
],
yAxis: [{
@ -154,23 +162,26 @@ const costOption = {
xAxis: [
{
type: 'category',
boundaryGap: true,
data: chartContext.categories
data: chartContext.categories,
axisLabel: {
formatter(value: string) {
return value.split(" ")[1]
}
}
}
],
yAxis: [
{
type: 'value',
scale: true,
name: 'cost(ms)',
name: 'rt(ms)',
min: 0,
boundaryGap: [0.2, 0.2]
}
],
series: [
{
name: 'cost',
type: 'bar',
name: 'rt',
type: 'line',
data: chartContext.data
}
]
@ -180,11 +191,13 @@ const updateChart = (data: MonitorData) => {
chartContext.data.shift()
chartContext.successData.shift()
chartContext.failureData.shift()
chartContext.categories.shift()
chartContext.cur--
}
chartContext.data.push(data.cost)
chartContext.data.push(data.cost / data.total)
chartContext.failureData.push(data.failed)
chartContext.successData.push(data.success)
chartContext.categories.push(data.timestamp)
chartContext.cur++
chartContext.myChart!.setOption<EChartsOption>({
@ -286,15 +299,16 @@ onBeforeUnmount(() => {
const submit = async (data: { classItem: Item, methodItem: Item, conditon: string }) => {
enhancer.value = undefined
// tableResults.length = 0
averageRT.value.totalCost =0
averageRT.value.totalCount = 0
let condition = data.conditon.trim() == "" ? "" : `'${data.conditon.trim()}'`
let cycle = `-c ${cycleV.value}`
fetchS.baseSubmit(fetchM, {
action: "async_exec",
command: `monitor -c 5 ${data.classItem.value} ${data.methodItem.value} ${condition}`,
command: `monitor ${cycle} ${data.classItem.value as string} ${data.methodItem.value} ${condition}`,
sessionId: undefined
}).then(
res => loop.open()
_res => loop.open()
)
}
</script>
@ -321,7 +335,9 @@ const submit = async (data: { classItem: Item, methodItem: Item, conditon: strin
<button class="btn btn-sm btn-outline" @click="changeCycle">cycle time:{{cycleV}}</button>
</template>
</MethodInput>
<Enhancer :result="enhancer" v-if="enhancer" class="mb-4"></Enhancer>
<Enhancer :result="enhancer" v-if="enhancer" class="mb-4">
</Enhancer>
<div id="monitorchart" class="input-btn-style h-60 w-full pointer-events-auto transition mb-2"></div>
<div id="monitorchartcost" class="input-btn-style h-60 w-full pointer-events-auto transition"></div>

@ -19,7 +19,7 @@ let eventList = reactive([] as string[]);
let selectEvent = ref("cpu")
let includesVal = reactive(new Set<string>())
let excludesVal = reactive(new Set<string>())
let framebuf = ref(1000000)
let framebuf = ref(1_000_000)
let duration = ref(300)
let profilerStatus = ref({
is: false,
@ -29,6 +29,7 @@ let outputPath = ref("")
let samples = ref(0)
const support = ref(false)
let fileformat = ref("%t-%p.html")
const getStatusLoop = fetchS.getPollingLoop(() => {
const statusM = interpret(permachine)
fetchS.baseSubmit(statusM, {
@ -55,7 +56,8 @@ const getStatusLoop = fetchS.getPollingLoop(() => {
}, {
step: 2000,
})
const handleFramebuf = publicS.numberCondition(framebuf, {})
const handleduration = publicS.numberCondition(duration, {})
const getSampleLoop = fetchS.getPollingLoop(() => {
let statusM = interpret(permachine)
fetchS.baseSubmit(statusM, {
@ -227,8 +229,16 @@ onBeforeUnmount(() => {
</ListboxOptions>
</div>
</Listbox>
<button class="btn btn-sm btn-outline mr-2" @click="changeDuration">duration :{{duration}}</button>
<button class="btn btn-sm btn-outline mr-2" @click="changeFramebuf">framebuf :{{framebuf}}</button>
<div class="btn-group mr-2">
<button class="btn btn-sm btn-outline" @click.prevent="handleduration.decrease">-</button>
<button class="btn btn-sm btn-outline border-x-0" @click.prevent="changeDuration">duration :{{duration}}</button>
<button class="btn btn-sm btn-outline" @click.prevent="handleduration.increase">+</button>
</div>
<div class="btn-group mr-2">
<button class="btn btn-sm btn-outline" @click.prevent="handleFramebuf.decrease">-</button>
<button class="btn btn-sm btn-outline border-x-0" @click.prevent="changeFramebuf">framebuf :{{framebuf}}</button>
<button class="btn btn-sm btn-outline" @click.prevent="handleFramebuf.increase">+</button>
</div>
<button class="btn btn-sm btn-outline mr-2" @click="changeFile">file :<span
class="normal-case">{{fileformat}}</span></button>
<TodoList title="include" :val-set="includesVal" class=" mr-2"></TodoList>

@ -91,16 +91,18 @@ const submit = async (data: { classItem: Item, methodItem: Item, conditon: strin
<MethodInput :submit-f="submit" ncondition ncount></MethodInput>
<Enhancer :result="enhancer" v-if="enhancer"></Enhancer>
<div class="w-full flex justify-center items-center mt-4">
<table class="table w-full table-compact group">
<div class="mt-4 overflow-x-auto w-full">
<table class="table w-full table-compact">
<thead>
<tr>
<th class="border border-slate-300" v-for="(v,i) in keyList" :key="i" :class="{'group-first:z-0':i===0}">{{v}}</th>
<th></th>
<th v-for="(v,i) in keyList" :key="i">{{v}}</th>
</tr>
</thead>
<tbody class="">
<tr v-for="(map, i) in tableResults" :key="i">
<td class="border border-slate-300" v-for="(key,j) in keyList" :key="j">
<th>{{i + 1}}</th>
<td v-for="(key,j) in keyList" :key="j">
<template v-if="key!== 'stackTrace'">
{{map.get(key)}}
</template>
@ -113,6 +115,12 @@ const submit = async (data: { classItem: Item, methodItem: Item, conditon: strin
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th></th>
<th v-for="(v,i) in keyList" :key="i">{{v}}</th>
</tr>
</tfoot>
</table>
</div>

@ -126,7 +126,7 @@ const submit = (data: { classItem: Item, methodItem: Item, conditon: string, cou
<MethodInput :submit-f="submit" class="mb-2" ncondition ncount>
<template #others>
<label class="label cursor-pointer btn-sm border border-neutral ml-2">
<label class="label cursor-pointer btn-sm ml-2">
<span class="label-text uppercase font-bold mr-1">skip JDK Method</span>
<input v-model="enabled" type="checkbox" class="toggle"/>
</label>

@ -173,7 +173,7 @@ const transform = (tf: TimeFragment) => {
} else {
val = (tf[k as tfkey].toString())
}
map.set(k, val)
})
updateChart(tf)
@ -187,9 +187,9 @@ getPullResultsEffect(
console.log(tf.index)
// if(!timeFragmentSet.has(tf.index)){
// timeFragmentSet.add(tf.index)
tableResults.unshift(transform(tf))
tableResults.unshift(transform(tf))
// }
})
}
if (result.type == "enhancer") {
@ -291,7 +291,7 @@ const searchTt = () => {
tableResults.unshift(transform(tf))
})
}
}).catch(err=>{
}).catch(err => {
console.error(err)
})
}
@ -327,35 +327,42 @@ const searchTt = () => {
</template>
</CmdResMenu>
</div>
<Enhancer :result="enhancer" v-if="enhancer"></Enhancer>
<div class="w-full flex justify-center items-center overflow-auto flex-1">
<table class="table table-compact group w-full">
<thead>
<tr>
<th class="border group-first:z-0" v-for="(v,i) in keyList" :key="i">{{v}}</th>
<th class="border">invoke</th>
</tr>
</thead>
<tbody class="">
<tr v-for="(map, i) in tableResults" :key="i">
<td class="border" v-for="(key,j) in keyList" :key="j">
<template v-if=" key !== 'params'">
{{map.get(key)}}
</template>
<Enhancer :result="enhancer" v-if="enhancer">
</Enhancer>
<div class="overflow-x-auto w-full">
<table class="table table-compact w-full">
<thead>
<tr>
<th></th>
<th class="normal-case" v-for="(v,i) in keyList" :key="i">{{v}}</th>
</tr>
</thead>
<tbody class="">
<tr v-for="(map, i) in tableResults" :key="i">
<th class="">
<button class="btn btn-primary btn-sm btn-outline" @click="reTrigger(map.get('index')!)">invoke</button>
</th>
<td class="" v-for="(key,j) in keyList" :key="j">
<template v-if=" key !== 'params'">
{{map.get(key)}}
</template>
<div class="flex flex-col" v-else>
<div v-for="(row, k) in map.get(key)" :key="k">
{{row}}
</div>
<div class="flex flex-col" v-else>
<div v-for="(row, k) in map.get(key)" :key="k">
{{row}}
</div>
</td>
<td class="border">
<button class="btn btn-primary btn-sm btn-outline" @click="reTrigger(map.get('index')!)">invoke</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th></th>
<th class="normal-case" v-for="(v,i) in keyList" :key="i">{{v}}</th>
</tr>
</tfoot>
</table>
</div>
</div>
</template>

@ -18,6 +18,7 @@ const pollResults = reactive([] as [string, Map<string, string[]>, TreeNode][])
const enhancer = ref(undefined as EnchanceResult | undefined)
const depth = ref(1)
const tableResults = reactive([] as Map<string, string | TreeNode>[])
const { increase, decrease } = publiC.numberCondition(depth, { min: 1, max: 6 })
const keyList = [
"ts",
"accessPoint",
@ -150,7 +151,8 @@ const submit = async (data: { classItem: Item, methodItem: Item, conditon: strin
<template #others>
<div class="relative group ml-2">
<div class="btn btn-sm btn-outline">watching point</div>
<div class="h-0 group-hover:h-auto group-focus-within:h-auto absolute overflow-clip transition z-10 top-full pt-2">
<div
class="h-0 group-hover:h-auto group-focus-within:h-auto absolute overflow-clip transition z-10 top-full pt-2">
<label class="label cursor-pointer btn-sm border border-neutral ml-2 bg-base-100"
v-for="(mode,i) in modereflist" :key="i">
@ -161,33 +163,36 @@ const submit = async (data: { classItem: Item, methodItem: Item, conditon: strin
</div>
</div>
<button class="btn btn-sm btn-outline ml-2" @click="setDepth">depth:{{depth}}</button>
<div class="btn-group ml-2">
<button class="btn btn-sm btn-outline" @click.prevent="decrease">-</button>
<button class="btn btn-sm btn-outline border-x-0" @click.prevent="setDepth">depth:{{depth}}</button>
<button class="btn btn-sm btn-outline" @click.prevent="increase">+</button>
</div>
</template>
</MethodInput>
<Enhancer :result="enhancer" v-if="enhancer"></Enhancer>
<div class="flex justify-center mt-4 overflow-auto">
<table class="table w-full group">
<div class="overflow-x-auto w-full mt-4">
<table class="table w-full table-compact">
<thead>
<tr>
<th class="border border-slate-300" v-for="(v,i) in keyList" :key="i" :class="{'group-first:z-0':i===0}">{{v}}
<th></th>
<th class="0" v-for="(v,i) in keyList" :key="i">{{v}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResults" :key="i">
<td class="border border-slate-300" v-for="(key,j) in keyList" :key="j">
<tr v-for="(map, i) in tableResults" :key="i" class="hover">
<th>{{i+1}}</th>
<td class="" v-for="(key,j) in keyList" :key="j">
<div v-if=" key !== 'value'">
{{map.get(key)}}
</div>
<div class="flex flex-col" v-else>
<Tree :root="(map.get('value') as TreeNode)" class="mt-2" button-class=" ">
<template #meta="{ data, active }">
<div
class="bg-info px-2 rounded-r rounded-br mr-2 text-info-content" :class='{
"hover:opacity-50":active
}'
>
<div class="bg-info px-2 rounded-r rounded-br mr-2 text-info-content" :class='{
"hover:opacity-50":active
}'>
{{data}}
</div>
</template>
@ -196,6 +201,14 @@ const submit = async (data: { classItem: Item, methodItem: Item, conditon: strin
</td>
</tr>
</tbody>
<tfoot>
<tr>
<th></th>
<th class="0" v-for="(v,i) in keyList" :key="i">{{v}}
</th>
</tr>
</tfoot>
</table>
</div>
</template>

@ -0,0 +1,67 @@
<script setup lang="ts">
import permachine from '@/machines/perRequestMachine';
import { fetchStore } from '@/stores/fetch';
import { onBeforeMount, reactive } from 'vue';
import { interpret } from 'xstate';
const fetchS = fetchStore();
type ResultType = { "key": string, "value": string};
const tableResultList: ResultType[] = reactive([])
// tree
const transformToString: <T=Record<string,unknown>>(obj:T)=>T = (obj)=>{
type Out = typeof obj
let output = {} as Out
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const element = obj[key];
if( typeof element === "object") {
output[key] = transformToString(element as Record<string,unknown>) as Out[Extract<keyof Out, string>]
} else {
output[key] = (element as (string|number|boolean)).toString() as Out[Extract<keyof Out, string>]
}
}
}
return output
}
const getJvm = () => fetchS.baseSubmit(interpret(permachine), {
action: "exec",
command: "jvm"
}).then(res => {
const result = (res as CommonRes).body.results[0]
if (result.type === "jvm") {
tableResultList.length = 0
Object.entries(result.jvmInfo).forEach(([key, value]) => {
let row = {
key,
value:JSON.stringify(value)
}
tableResultList.push(row)
})
}
})
onBeforeMount(() => {
getJvm()
})
</script>
<template>
<table class="table w-full table-compact">
<thead>
<tr>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResultList" :key="i" class="hover">
<th>{{map.key}}</th>
<td>{{map.value}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>key</th>
<th>value</th>
</tr>
</tfoot>
</table>
</template>

@ -0,0 +1,102 @@
<script setup lang="ts">
import permachine from '@/machines/perRequestMachine';
import { fetchStore } from '@/stores/fetch';
import { publicStore } from '@/stores/public';
import { onBeforeMount, reactive, ref, Ref } from 'vue';
import { interpret } from 'xstate';
const fetchS = fetchStore();
const publicS = publicStore()
type ResultType = MergeObj<Omit<GlobalOptions, "value">, {
value: Ref<string>, changeValue: null | (() => void)
}>
const tableResultList: ResultType[] = reactive([])
const keyList: (keyof GlobalOptions)[] = [
"level",
"name",
"type",
"value",
"summary",
"description",
]
const setVmoption = (key: string, value: string) => fetchS.baseSubmit(interpret(permachine), {
action: "exec",
command: `options ${key} ${value}`
})
const getVmoption = () => fetchS.baseSubmit(interpret(permachine), {
action: "exec",
command: "options",
}).then(res => {
let result = (res as CommonRes).body.results[0]
if (result.type == "options") {
tableResultList.length = 0;
result.options.forEach((option) => {
let rows: ResultType[] = []
//
let _raw = ref(option.value)
let changeValue = null
changeValue = publicS.inputDialogFactory(_raw,
(raw) => {
setVmoption(option.name, raw.trim())
.then(res =>{
let result = (res as CommonRes).body.results[0]
if(result.type === "options") _raw.value = (result.changeResult.afterValue as string).toString()
})
.catch(err => {
// 退
_raw.value = option.value
})
return raw.trim()
},
(input) => input.value)
rows.push({
...option,
value: _raw,
changeValue,
})
tableResultList.push(...rows)
})
tableResultList.sort((a, b) => {
if(a.level != b.level) return a.level - b.level
else {
return a.name > b.name ? 1 :-1
}
})
}
})
onBeforeMount(() => {
getVmoption()
})
</script>
<template>
<table class="table w-full table-compact">
<thead>
<tr>
<th></th>
<th v-for="(k, i) in keyList" :key="i">{{ k }}</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResultList" :key="i" class="hover">
<th>
<button class="btn btn-outline btn-xs btn-primary" @click.prevent="map.changeValue"
v-if="map.changeValue !== null">edit</button>
</th>
<template v-for="(k, j) in keyList" :key="j">
<th v-if="k === 'name' || k === 'level'">{{ map[k] }}</th>
<td v-else class="break-words"> {{ map[k] }}</td>
</template>
</tr>
</tbody>
<tfoot>
<tr>
<th></th>
<th v-for="(k, i) in keyList" :key="i">{{ k }}</th>
</tr>
</tfoot>
</table>
</template>

@ -0,0 +1,69 @@
<script setup lang="ts">
import permachine from '@/machines/perRequestMachine';
import { fetchStore } from '@/stores/fetch';
import { onBeforeMount, reactive } from 'vue';
import { interpret } from 'xstate';
const fetchS = fetchStore();
type ResultType = MergeObj<Perfcounter,{rowspan:number}>
const perfcounterList: ResultType[] = reactive([])
let keyList: (keyof Perfcounter)[] = [
"name",
"units",
"variability",
"value",
]
const getPerCounter = () => fetchS.baseSubmit(interpret(permachine), { action: "exec", command: "perfcounter -d" }).then(res => {
const result = (res as CommonRes).body.results[0]
if (result.type === "perfcounter") {
const perfcounters = result.perfCounters
perfcounterList.length = 0;
perfcounters.forEach(perfcouter => {
let result = {...perfcouter,rowspan:1}
result.value = result.value.toString()
perfcounterList.push(result)
})
perfcounterList.sort((a, b) => a.name > b.name ? 1 : -1)
}
})
onBeforeMount(() => {
getPerCounter()
})
</script>
<template>
<table class="table w-full table-compact">
<thead>
<tr>
<th v-for="(v,i) in keyList" :key="i">{{v}}</th>
</tr>
</thead>
<tbody class="">
<tr v-for="(map, i) in perfcounterList" :key="i" class="hover">
<template v-for="(key,j) in keyList" :key="j">
<!-- 展示合并的单元格且定住name -->
<th v-if="key == 'name' && map.rowspan > 0" :rowspan="map.rowspan">
{{map[key]}}
</th>
<!-- 只有value才会裂变 -->
<td v-else-if="key === 'value'" >
<div class="break-all">{{map[key]}}</div>
</td>
<!-- 展示合并的单元格 -->
<td v-else-if="map.rowspan > 0" :rowspan="map.rowspan">
{{map[key]}}
</td>
</template>
</tr>
</tbody>
<tfoot>
<tr>
<th v-for="(v,i) in keyList" :key="i" class="break-words">{{v}}</th>
</tr>
</tfoot>
</table>
</template>
<style scoped>
</style>

@ -0,0 +1,52 @@
<script setup lang="ts">
import permachine from '@/machines/perRequestMachine';
import { fetchStore } from '@/stores/fetch';
import { onBeforeMount, reactive } from 'vue';
import { interpret } from 'xstate';
const fetchS = fetchStore();
type ResultType = { "key": string, "value": string, rowspan: number };
const tableResultList: ResultType[] = reactive([])
const getSysenv = () => fetchS.baseSubmit(interpret(permachine), {
action: "exec",
command: "sysenv",
}).then(res => {
tableResultList.length = 0
let result = (res as CommonRes).body.results[0]
if (result.type == "sysenv") {
Object.entries(result.env).forEach(([key, value]) => {
let rows: ResultType[] = []
rows.push({
key, value, rowspan: 1
})
tableResultList.push(...rows)
})
tableResultList.sort((a, b) => a.key > b.key ? 1 : -1)
}
})
onBeforeMount(() => {
getSysenv()
})
</script>
<template>
<table class="table w-full table-compact">
<thead>
<tr>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResultList" :key="i" class="hover">
<th v-if="map.rowspan > 0" :rowspan="map.rowspan">{{map.key}}</th>
<td>{{map.value}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>key</th>
<th>value</th>
</tr>
</tfoot>
</table>
</template>

@ -0,0 +1,78 @@
<script setup lang="ts">
import permachine from '@/machines/perRequestMachine';
import { fetchStore } from '@/stores/fetch';
import { publicStore } from '@/stores/public';
import { onBeforeMount, reactive, ref, Ref } from 'vue';
import { interpret } from 'xstate';
const fetchS = fetchStore();
const publicS = publicStore()
type ResultType = { "key": string, "value": Ref<string>, rowspan: number, changeValue:()=>void};
const tableResultList: ResultType[] = reactive([])
const setSysprop = (key:string,value:string) => fetchS.baseSubmit(interpret(permachine),{
action: "exec",
command:`sysprop ${key} ${value}`
})
const getSysprop = () => fetchS.baseSubmit(interpret(permachine), {
action: "exec",
command: "sysprop",
}).then(res => {
let result = (res as CommonRes).body.results[0]
if (result.type == "sysprop") {
tableResultList.length = 0;
Object.entries(result.props).forEach(([key, value]) => {
let rows: ResultType[] = []
//
let _raw = ref(value)
const changeValue = publicS.inputDialogFactory(_raw,
(raw) => {
setSysprop(key, raw.trim()).then(res=>{
},err=>{
// 退
_raw.value = value
})
return raw.trim()
},
(input) => input.value)
rows.push({
key, value:_raw, rowspan: 1, changeValue
})
tableResultList.push(...rows)
})
tableResultList.sort((a, b) => a.key > b.key ? 1 : -1)
}
})
onBeforeMount(() => {
getSysprop()
})
</script>
<template>
<table class="table w-full table-compact">
<thead>
<tr>
<th></th>
<th>key</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResultList" :key="i" class="hover">
<th v-if="map.rowspan > 0" :rowspan="map.rowspan">
<button class="btn btn-outline btn-xs btn-primary" @click.prevent="map.changeValue">edit</button>
</th>
<th v-if="map.rowspan > 0" :rowspan="map.rowspan">{{map.key}}</th>
<td>{{map.value}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th></th>
<th>key</th>
<th>value</th>
</tr>
</tfoot>
</table>
</template>

@ -0,0 +1,92 @@
<script setup lang="ts">
import permachine from '@/machines/perRequestMachine';
import { fetchStore } from '@/stores/fetch';
import { publicStore } from '@/stores/public';
import { onBeforeMount, reactive, ref, Ref } from 'vue';
import { interpret } from 'xstate';
const fetchS = fetchStore();
const publicS = publicStore()
type ResultType = { name: string, origin: string, value: Ref<string>, writeable: string, changeValue: null|(() => void)
};
const tableResultList: ResultType[] = reactive([])
const keyList: (keyof VmOption)[] = [
"name",
"origin",
"writeable",
"value",
]
const setVmoption = (key: string, value: string) => fetchS.baseSubmit(interpret(permachine), {
action: "exec",
command: `vmoption ${key} ${value}`
})
const getVmoption = () => fetchS.baseSubmit(interpret(permachine), {
action: "exec",
command: "vmoption",
}).then(res => {
let result = (res as CommonRes).body.results[0]
if (result.type == "vmoption") {
tableResultList.length = 0;
result.vmOptions.forEach((vmoption) => {
let rows: ResultType[] = []
//
let _raw = ref(vmoption.value)
let changeValue = null
if(vmoption.writeable===true) {
changeValue = publicS.inputDialogFactory(_raw,
(raw) => {
setVmoption(vmoption.name, raw.trim()).then(res => {
}, err => {
// 退
_raw.value = vmoption.value
})
return raw.trim()
},
(input) => input.value)
}
rows.push({
name: vmoption.name,
value: _raw,
changeValue,
writeable: vmoption.writeable.toString(),
origin: vmoption.origin
})
tableResultList.push(...rows)
})
tableResultList.sort((a, b) => a.name > b.name ? 1 : -1)
}
})
onBeforeMount(() => {
getVmoption()
})
</script>
<template>
<table class="table w-full table-compact">
<thead>
<tr>
<th></th>
<th v-for="(k, i) in keyList" :key="i">{{k}}</th>
</tr>
</thead>
<tbody>
<tr v-for="(map, i) in tableResultList" :key="i" class="hover">
<th >
<button class="btn btn-outline btn-xs btn-primary" @click.prevent="map.changeValue" v-if="map.changeValue !== null">edit</button>
</th>
<template v-for="(k,j) in keyList" :key="j">
<th v-if="k==='name'">{{map[k]}}</th>
<td v-else class="break-words"> {{map[k]}}</td>
</template>
</tr>
</tbody>
<tfoot>
<tr>
<th></th>
<th v-for="(k, i) in keyList" :key="i">{{k}}</th>
</tr>
</tfoot>
</table>
</template>

@ -15,30 +15,7 @@ const classFields = reactive(new Map<string, string[]>())
const classMethodMap = reactive(new Map<string, string[]>())
const dumpMap = reactive(new Map<string, string[]>())
const { getCommonResEffect } = publicStore()
const publicS = publicStore()
const fetchS = fetchStore()
// getCommonResEffect(classInfoM, body => {
// const result = body.results[0]
// if (result.type === "sc" && result.detailed === true && result.withField === true) {
// classDetailMap.clear()
// classFields.clear()
// Object.entries(result.classInfo).filter(([k, v]) => k !== "fields").forEach(([k, v]) => {
// let value: string[] = []
// if (!["interfaces", "annotations", "classloader", "superClass"].includes(k)) value.push(v.toString())
// else value = v as string[]
// classDetailMap.set(k, value)
// })
// result.classInfo.fields.forEach(field => {
// classFields.set(field.name, Object.entries(field).filter(([k, v]) => k !== "name").map(([k, v]) => {
// if (k === "value") v = JSON.stringify(v)
// return `${k}: ${v}`
// }))
// })
// }
// })
getCommonResEffect(classMethodInfoM, body => {
classMethodMap.clear()
body.results.forEach(result => {

@ -140,9 +140,9 @@ const getCategorizedByClassType = () => {
for (const name in result.classLoaderStats) {
const map = new Map()
for (const key in result.classLoaderStats[name]) {
map.set(key, result.classLoaderStats[name][key])
}
map.set("loadedCount", result.classLoaderStats[name].loadedCount)
map.set("numberOfInstance", result.classLoaderStats[name].numberOfInstance)
// "loadedCount"|"numberOfInstance"
map.set("name", name)
tableResults.push(map)
}
@ -250,7 +250,8 @@ const resetClassloader = () => {
</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"
<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>
@ -260,13 +261,12 @@ const resetClassloader = () => {
</div>
</div>
</div>
<div class="w-1/3 ml-2 overflow-y-scroll transition-all duration-500" :class='{
<div class=" ml-2 overflow-y-scroll transition-all duration-500" :class='{
"w-0":loaderCache.hash === "",
"input-btn-style":loaderCache.hash !==""
"input-btn-style w-1/3":loaderCache.hash !==""
}'>
<!-- <div class="overflow-auto h-full"> -->
<div class="mb-2">
<div class="overflow-auto">
<span class="bg-primary-focus px-2 rounded-l text-primary-content border border-primary-focus">
@ -293,7 +293,6 @@ const resetClassloader = () => {
</span>
</div>
</div>
<template v-if="loaderCache.hash.trim() !== ''">
<div class="flex mb-2 w-full">
<div class=" cursor-default
@ -351,20 +350,26 @@ const resetClassloader = () => {
<button class="btn btn-primary btn-sm" @click="getCategorizedByClassType">refresh</button>
</div>
<div class="overflow-auto">
<table class="table w-full group table-compact">
<thead>
<tr>
<th class="border border-slate-300 p-2" 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">
<td class="border border-slate-300 p-2" v-for="(key,j) in keyList" :key="j">
{{map.get(key)}}
</td>
</tr>
</tbody>
</table>
<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>
</div>
</div>

@ -46,10 +46,10 @@ const submitCommand = (e: Event) => {
class="w-full border-none py-2 pl-3 pr-10 leading-5 text-gray-900 focus-visible:outline-none">
</div>
<label class="label cursor-pointer btn-sm border border-neutral mr-2">
<span class="label-text uppercase font-bold mr-1">only live object</span>
<input v-model="enabled" type="checkbox" class="toggle" />
</label>
<label class="label cursor-pointer btn-sm mr-2">
<span class="label-text uppercase font-bold mr-1">only live object</span>
<input v-model="enabled" type="checkbox" class="toggle" />
</label>
</label>
<button @click.prevent="submitCommand"

@ -23,6 +23,7 @@ const setDepth = publiC.inputDialogFactory(
},
(input) => input.value.toString(),
)
const {increase, decrease} = publiC.numberCondition(depth,{min:1})
const setHash = publiC.inputDialogFactory(
hashcode,
(raw) => raw,
@ -67,7 +68,11 @@ const getSource = () => {
<input type="text" v-model="express"
class="w-full border-none py-2 pl-3 pr-10 leading-5 text-gray-900 focus-visible:outline-none">
</div>
<button class="btn btn-sm btn-outline mr-2" @click.prevent="setDepth">depth:{{depth}}</button>
<div class="btn-group mr-2">
<button class="btn btn-outline btn-sm" @click.prevent="decrease">-</button>
<button class="btn btn-outline btn-sm border-x-0" @click.prevent="setDepth">depth:{{depth}}</button>
<button class="btn btn-outline btn-sm" @click.prevent="increase">+</button>
</div>
<button class="btn btn-sm btn-outline mr-2" @click.prevent="setClassLoader" v-if="hashcode === ''">ClassLoaderClass:{{classloaderName}}</button>
<button class="btn btn-sm btn-outline mr-2" @click.prevent="setHash" v-if="classloaderName === ''">hashcode:{{hashcode}}</button>
</label>

@ -69,7 +69,7 @@ const openList = () => {
class="w-full border-none py-2 pl-3 pr-10 leading-5 text-gray-900 focus-visible:outline-none">
</div>
</label>
<label class="label cursor-pointer btn-sm border border-neutral mr-2">
<label class="label cursor-pointer btn-sm mr-2">
<span class="label-text uppercase font-bold mr-1">explicitly trigger</span>
<input v-model="enabled" type="checkbox" class="toggle" />
</label>

@ -1,7 +1,7 @@
<script setup lang="ts">
// import machine from '@/machines/consoleMachine';
import { useInterpret, } from '@xstate/vue';
import { onBeforeMount, reactive, ref } from 'vue';
import { onBeforeMount, reactive, ref, computed } from 'vue';
import { fetchStore } from '@/stores/fetch';
import { publicStore } from '@/stores/public';
import TodoList from '@/components/input/TodoList.vue';
@ -10,7 +10,7 @@ import {
} from '@headlessui/vue';
import { transfromStore } from "@/stores/resTransform"
import permachine from '@/machines/perRequestMachine';
import { computed } from '@vue/reactivity';
import { watch } from 'fs';
const fetchS = fetchStore()
const FetchService = useInterpret(permachine)
@ -43,7 +43,8 @@ const keyList: thkey[] = [
"blockedCount",
"blockedTime",
]
const statsList: (keyof ThreadStats)[] = ["id",
const statsList: (keyof ThreadStats)[] = [
"id",
"name",
"cpu",
"daemon",
@ -62,9 +63,15 @@ 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 = tableResults
let res = count.value > 0 ? tableResults.filter((v, i)=>i < count.value) : tableResults
if (includesVal.size === 0) return res;
//
includesVal.forEach((v1) => {
@ -106,8 +113,9 @@ onBeforeMount(() => {
})
const getThreads = () => {
let i = leastTime.value > 0 ? "-i " + leastTime.value : ""
let n = count.value > 0 ? "-n " + count.value : ""
const b = isBlock.value ? "-b" : ""
// block
let n = count.value > 0 && !isBlock ? "-n " + count.value : ""
const b = isBlock.value ? "-b --lockedMonitors --lockedSynchronizers" : ""
let state = threadState.value.value === "" ? "" : `--state ${threadState.value.value}`
tableResults.length = 0
for (const key in infoCount.value) {
@ -173,12 +181,12 @@ const setleast = publiC.inputDialogFactory(
},
(input) => input.value.toString(),
)
const {increase, decrease} = publiC.numberCondition(count,{min:0})
const getSpecialThreads = (threadid: number = -1) => {
let threadName = threadid > 0 ? `${threadid}` : ""
fetchS.baseSubmit(FetchService, {
action: "exec",
command: `thread ${threadName}`
command: `thread ${threadName} `
}).then(res => {
const result = (res as CommonRes).body.results[0]
if (result.type === "thread") {
@ -195,12 +203,12 @@ const getSpecialThreads = (threadid: number = -1) => {
<div class="flex justify-end items-center h-[10vh]">
<TodoList title="filter" :val-set="includesVal" class=" mr-2"></TodoList>
<label class="label cursor-pointer btn-sm border border-neutral ">
<span class="label-text uppercase font-bold mr-1">is blocking:</span>
<input v-model="isBlock" type="checkbox" class="toggle"/>
</label>
<button class="btn ml-2 btn-sm btn-outline" @click="setleast">sample interval:{{leastTime}}</button>
<button v-show="!isBlock" class="btn ml-2 btn-sm btn-outline" @click="setlimit"> top n threads:{{count}}</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" @click.prevent="increase">+</button>
</div>
<Listbox v-model="threadState">
<div class=" relative mx-2 ">
<ListboxButton class="btn w-40 btn-sm btn-outline">state {{ threadState.name }}</ListboxButton>
@ -217,7 +225,11 @@ const getSpecialThreads = (threadid: number = -1) => {
</ListboxOptions>
</div>
</Listbox>
<button class="btn btn-primary btn-sm btn-outline" @click="getThreads"> get threads</button>
<label class="label cursor-pointer btn-sm ">
<span class="label-text uppercase font-bold mr-1">is blocking:</span>
<input v-model="isBlock" type="checkbox" class="toggle" />
</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">
@ -231,31 +243,31 @@ const getSpecialThreads = (threadid: number = -1) => {
</div>
</div>
<div class="overflow-auto h-[40vh] w-full">
<table class="table w-full group">
<table class="table w-full">
<thead>
<tr>
<th class="border border-slate-300 p-2 group-first:z-0">get stackTrace</th>
<template v-if="count===0">
<th class="border border-slate-300 p-2" v-for="(v,i) in keyList" :key="i">{{v}}</th>
<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="border border-slate-300 p-2" v-for="(v,i) in statsList" :key="i">{{v}}</th>
<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">
<td class="border border-slate-300 p-2"><button class="btn-outline btn-primary btn btn-sm"
<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></td>
</button></th>
<template v-if="count === 0">
<td class="border border-slate-300 p-2" v-for="(key,j) in keyList" :key="j">
<td class="" v-for="(key,j) in keyList" :key="j">
{{map.get(key)}}
</td>
</template>
<template v-else>
<td class="border border-slate-300 p-2" v-for="(key,j) in statsList" :key="j">
<td class="" v-for="(key,j) in statsList" :key="j">
{{map.get(key)}}
</td>
</template>

@ -11,6 +11,7 @@ const gcMachine = useInterpret(permachine)
const fetchS = fetchStore()
const publicS = publicStore()
const depth = ref(1)
const {increase, decrease} = publicS.numberCondition(depth,{min:1})
const setDepth = publicS.inputDialogFactory(
depth,
(raw) => {
@ -87,7 +88,11 @@ const getInstance = (data:{classItem:Item}) => {
<ClassInput :submit-f="getInstance" class="mb-4" >
<template #others>
<button class="ml-2 btn btn-outline btn-sm" @click="setDepth">depth:{{depth}}</button>
<div class="btn-group ml-2">
<button class="btn btn-outline btn-sm" @click.prevent="decrease">-</button>
<button class="btn btn-outline btn-sm border-x-0" @click.prevent="setDepth">depth:{{depth}}</button>
<button class="btn btn-outline btn-sm" @click.prevent="increase">+</button>
</div>
</template>
</ClassInput>
<template v-if="pollResults.length > 0">

@ -5,8 +5,25 @@ import * as path from "path";
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
const proxyTarget =`${env.VITE_ARTHAS_PROXY_IP}:${env.VITE_ARTHAS_PROXY_PORT}`;
const proxyTarget =
`${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`
input = {
tunnel: path.resolve(__dirname, "index.html")
}
} else {
outDir = `./dist`
input = {
main: path.resolve(__dirname, "index.html"),
ui: path.resolve(__dirname, "ui/index.html"),
}
}
return {
plugins: [vue({
reactivityTransform: true,
@ -18,12 +35,10 @@ export default defineConfig(({ mode }) => {
},
build: {
emptyOutDir: true,
outDir,
minify: "esbuild",
rollupOptions: {
input: {
main: path.resolve(__dirname, "index.html"),
ui: path.resolve(__dirname, "ui/index.html"),
},
input,
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
@ -43,7 +58,7 @@ export default defineConfig(({ mode }) => {
"/api": {
target: `http://${proxyTarget}`,
changeOrigin: true,
}
},
},
},
};

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save