2020-11-01 03:39:38 +01:00
|
|
|
<template>
|
|
|
|
<XWindow ref="window" :initial-width="650" :initial-height="420" :can-resize="true" @closed="$emit('closed')">
|
|
|
|
<template #header>
|
|
|
|
<Fa :icon="faTerminal" style="margin-right: 0.5em;"/>Task Manager
|
|
|
|
</template>
|
|
|
|
<div class="qljqmnzj">
|
2020-11-01 05:38:48 +01:00
|
|
|
<MkTab v-model:value="tab" :items="[{ label: 'Windows', value: 'windows', }, { label: 'Stream', value: 'stream', }, { label: 'Stream (Pool)', value: 'streamPool', }, { label: 'API', value: 'api', }]" style="border-bottom: solid 1px var(--divider);"/>
|
|
|
|
|
2020-11-01 06:05:06 +01:00
|
|
|
<div class="content">
|
2020-11-01 14:09:16 +01:00
|
|
|
<div v-if="tab === 'windows'" class="windows" v-follow>
|
2020-11-01 06:05:06 +01:00
|
|
|
<div class="header">
|
|
|
|
<div>#ID</div>
|
|
|
|
<div>Component</div>
|
|
|
|
<div>Action</div>
|
|
|
|
</div>
|
|
|
|
<div v-for="p in popups">
|
|
|
|
<div>#{{ p.id }}</div>
|
|
|
|
<div>{{ p.component.name ? p.component.name : '<anonymous>' }}</div>
|
|
|
|
<div><button class="_textButton" @click="killPopup(p)">Kill</button></div>
|
|
|
|
</div>
|
2020-11-01 05:38:48 +01:00
|
|
|
</div>
|
2020-11-01 14:09:16 +01:00
|
|
|
<div v-if="tab === 'stream'" class="stream" v-follow>
|
2020-11-01 06:05:06 +01:00
|
|
|
<div class="header">
|
|
|
|
<div>#ID</div>
|
|
|
|
<div>Ch</div>
|
|
|
|
<div>Handle</div>
|
|
|
|
<div>In</div>
|
|
|
|
<div>Out</div>
|
|
|
|
</div>
|
|
|
|
<div v-for="c in connections">
|
|
|
|
<div>#{{ c.id }}</div>
|
|
|
|
<div>{{ c.channel }}</div>
|
|
|
|
<div v-if="c.users !== null">(shared)<span v-if="c.name">{{ ' ' + c.name }}</span></div>
|
|
|
|
<div v-else>{{ c.name ? c.name : '<anonymous>' }}</div>
|
|
|
|
<div>{{ c.in }}</div>
|
|
|
|
<div>{{ c.out }}</div>
|
|
|
|
</div>
|
2020-11-01 05:38:48 +01:00
|
|
|
</div>
|
2020-11-01 14:09:16 +01:00
|
|
|
<div v-if="tab === 'streamPool'" class="streamPool" v-follow>
|
2020-11-01 06:05:06 +01:00
|
|
|
<div class="header">
|
|
|
|
<div>#ID</div>
|
|
|
|
<div>Ch</div>
|
|
|
|
<div>Users</div>
|
|
|
|
</div>
|
|
|
|
<div v-for="p in pools">
|
|
|
|
<div>#{{ p.id }}</div>
|
|
|
|
<div>{{ p.channel }}</div>
|
|
|
|
<div>{{ p.users }}</div>
|
|
|
|
</div>
|
2020-11-01 05:38:48 +01:00
|
|
|
</div>
|
2020-11-01 14:09:16 +01:00
|
|
|
<div v-if="tab === 'api'" class="api" v-follow>
|
|
|
|
<div class="header">
|
|
|
|
<div>#ID</div>
|
|
|
|
<div>Endpoint</div>
|
|
|
|
<div>State</div>
|
|
|
|
</div>
|
2020-11-01 14:43:19 +01:00
|
|
|
<div v-for="req in apiRequests" @click="showReq(req)">
|
2020-11-01 14:09:16 +01:00
|
|
|
<div>#{{ req.id }}</div>
|
|
|
|
<div>{{ req.endpoint }}</div>
|
|
|
|
<div class="state" :class="req.state">{{ req.state }}</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2020-11-01 05:38:48 +01:00
|
|
|
</div>
|
2020-11-01 06:05:06 +01:00
|
|
|
|
|
|
|
<footer>
|
|
|
|
<div><span class="label">Windows</span>{{ popups.length }}</div>
|
|
|
|
<div><span class="label">Stream</span>{{ connections.length }}</div>
|
|
|
|
<div><span class="label">Stream (Pool)</span>{{ pools.length }}</div>
|
|
|
|
</footer>
|
2020-11-01 03:39:38 +01:00
|
|
|
</div>
|
|
|
|
</XWindow>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script lang="ts">
|
2020-11-01 05:38:48 +01:00
|
|
|
import { defineComponent, markRaw, onBeforeUnmount, ref, shallowRef } from 'vue';
|
2020-11-01 03:39:38 +01:00
|
|
|
import { faTerminal } from '@fortawesome/free-solid-svg-icons';
|
|
|
|
import XWindow from '@/components/ui/window.vue';
|
|
|
|
import MkTab from '@/components/tab.vue';
|
|
|
|
import MkButton from '@/components/ui/button.vue';
|
2020-11-01 14:09:16 +01:00
|
|
|
import follow from '@/directives/follow-append';
|
2020-11-01 03:39:38 +01:00
|
|
|
import * as os from '@/os';
|
|
|
|
|
|
|
|
export default defineComponent({
|
|
|
|
components: {
|
|
|
|
XWindow,
|
|
|
|
MkTab,
|
|
|
|
MkButton,
|
|
|
|
},
|
|
|
|
|
2020-11-01 14:09:16 +01:00
|
|
|
directives: {
|
|
|
|
follow
|
|
|
|
},
|
|
|
|
|
2020-11-01 03:39:38 +01:00
|
|
|
props: {
|
|
|
|
},
|
|
|
|
|
|
|
|
emits: ['closed'],
|
|
|
|
|
|
|
|
setup() {
|
2020-11-01 05:38:48 +01:00
|
|
|
const connections = shallowRef([]);
|
|
|
|
const pools = shallowRef([]);
|
2020-11-01 03:39:38 +01:00
|
|
|
const refreshStreamInfo = () => {
|
2020-11-01 05:38:48 +01:00
|
|
|
console.log(os.stream.sharedConnectionPools, os.stream.sharedConnections, os.stream.nonSharedConnections);
|
|
|
|
const conn = os.stream.sharedConnections.map(c => ({
|
2020-11-01 03:39:38 +01:00
|
|
|
id: c.id, name: c.name, channel: c.channel, users: c.pool.users, in: c.inCount, out: c.outCount,
|
|
|
|
})).concat(os.stream.nonSharedConnections.map(c => ({
|
|
|
|
id: c.id, name: c.name, channel: c.channel, users: null, in: c.inCount, out: c.outCount,
|
2020-11-01 05:38:48 +01:00
|
|
|
})));
|
|
|
|
conn.sort((a, b) => (a.id > b.id) ? 1 : -1);
|
|
|
|
connections.value = conn;
|
|
|
|
pools.value = os.stream.sharedConnectionPools;
|
2020-11-01 03:39:38 +01:00
|
|
|
};
|
|
|
|
const interval = setInterval(refreshStreamInfo, 1000);
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
clearInterval(interval);
|
|
|
|
});
|
|
|
|
|
2020-11-01 05:38:48 +01:00
|
|
|
const killPopup = p => {
|
|
|
|
os.popups.value = os.popups.value.filter(x => x !== p);
|
|
|
|
};
|
|
|
|
|
2020-11-01 14:43:19 +01:00
|
|
|
const showReq = async req => {
|
|
|
|
os.popup(await import('./taskmanager.api-window.vue'), {
|
|
|
|
req: req
|
|
|
|
}, {
|
|
|
|
}, 'closed');
|
|
|
|
};
|
|
|
|
|
2020-11-01 03:39:38 +01:00
|
|
|
return {
|
2020-11-01 05:38:48 +01:00
|
|
|
tab: ref('stream'),
|
|
|
|
popups: os.popups,
|
2020-11-01 14:09:16 +01:00
|
|
|
apiRequests: os.apiRequests,
|
2020-11-01 03:39:38 +01:00
|
|
|
connections,
|
2020-11-01 05:38:48 +01:00
|
|
|
pools,
|
|
|
|
killPopup,
|
2020-11-01 14:43:19 +01:00
|
|
|
showReq,
|
2020-11-01 03:39:38 +01:00
|
|
|
faTerminal,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.qljqmnzj {
|
2020-11-01 06:05:06 +01:00
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
height: 100%;
|
|
|
|
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
|
|
|
|
|
|
|
|
> .content {
|
|
|
|
flex: 1;
|
|
|
|
overflow: auto;
|
|
|
|
|
2020-11-01 14:09:16 +01:00
|
|
|
> div {
|
2020-11-01 06:05:06 +01:00
|
|
|
display: table;
|
|
|
|
width: 100%;
|
|
|
|
padding: 16px;
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
|
|
> div {
|
|
|
|
display: table-row;
|
|
|
|
|
2020-11-01 14:43:19 +01:00
|
|
|
&:nth-child(even) {
|
|
|
|
//background: rgba(0, 0, 0, 0.1);
|
|
|
|
}
|
|
|
|
|
2020-11-01 06:05:06 +01:00
|
|
|
&.header {
|
|
|
|
opacity: 0.7;
|
|
|
|
}
|
|
|
|
|
2020-11-01 14:09:16 +01:00
|
|
|
> div {
|
2020-11-01 06:05:06 +01:00
|
|
|
display: table-cell;
|
2020-11-01 14:09:16 +01:00
|
|
|
white-space: nowrap;
|
|
|
|
|
|
|
|
&:not(:last-child) {
|
|
|
|
padding-right: 8px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&.api {
|
|
|
|
> div {
|
|
|
|
> .state {
|
|
|
|
&.pending {
|
|
|
|
color: var(--warn);
|
|
|
|
}
|
|
|
|
|
|
|
|
&.success {
|
|
|
|
color: var(--success);
|
|
|
|
}
|
|
|
|
|
|
|
|
&.failed {
|
|
|
|
color: var(--error);
|
|
|
|
}
|
|
|
|
}
|
2020-11-01 06:05:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
> footer {
|
|
|
|
display: flex;
|
2020-11-01 03:39:38 +01:00
|
|
|
width: 100%;
|
2020-11-01 06:05:06 +01:00
|
|
|
padding: 8px 16px;
|
2020-11-01 03:39:38 +01:00
|
|
|
box-sizing: border-box;
|
2020-11-01 06:05:06 +01:00
|
|
|
border-top: solid 1px var(--divider);
|
|
|
|
font-size: 0.9em;
|
2020-11-01 03:39:38 +01:00
|
|
|
|
|
|
|
> div {
|
2020-11-01 06:05:06 +01:00
|
|
|
flex: 1;
|
2020-11-01 03:39:38 +01:00
|
|
|
|
2020-11-01 06:05:06 +01:00
|
|
|
> .label {
|
2020-11-01 03:39:38 +01:00
|
|
|
opacity: 0.7;
|
2020-11-01 06:05:06 +01:00
|
|
|
margin-right: 0.5em;
|
2020-11-01 03:39:38 +01:00
|
|
|
|
2020-11-01 06:05:06 +01:00
|
|
|
&:after {
|
|
|
|
content: ":";
|
|
|
|
}
|
2020-11-01 03:39:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|