mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-30 11:33:10 +02:00
Improve task manager etc
This commit is contained in:
parent
21b6e23e98
commit
7060625adf
7 changed files with 108 additions and 23 deletions
|
@ -169,15 +169,15 @@ export default defineComponent({
|
|||
font-size: 32px;
|
||||
|
||||
&.success {
|
||||
color: var(--accent);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
&.error {
|
||||
color: #ec4137;
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
color: #ecb637;
|
||||
color: var(--warn);
|
||||
}
|
||||
|
||||
> * {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<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);"/>
|
||||
|
||||
<div class="content">
|
||||
<div v-if="tab === 'windows'" class="windows">
|
||||
<div v-if="tab === 'windows'" class="windows" v-follow>
|
||||
<div class="header">
|
||||
<div>#ID</div>
|
||||
<div>Component</div>
|
||||
|
@ -19,7 +19,7 @@
|
|||
<div><button class="_textButton" @click="killPopup(p)">Kill</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="tab === 'stream'" class="stream">
|
||||
<div v-if="tab === 'stream'" class="stream" v-follow>
|
||||
<div class="header">
|
||||
<div>#ID</div>
|
||||
<div>Ch</div>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<div>{{ c.out }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="tab === 'streamPool'" class="streamPool">
|
||||
<div v-if="tab === 'streamPool'" class="streamPool" v-follow>
|
||||
<div class="header">
|
||||
<div>#ID</div>
|
||||
<div>Ch</div>
|
||||
|
@ -48,6 +48,18 @@
|
|||
<div>{{ p.users }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="tab === 'api'" class="api" v-follow>
|
||||
<div class="header">
|
||||
<div>#ID</div>
|
||||
<div>Endpoint</div>
|
||||
<div>State</div>
|
||||
</div>
|
||||
<div v-for="req in apiRequests">
|
||||
<div>#{{ req.id }}</div>
|
||||
<div>{{ req.endpoint }}</div>
|
||||
<div class="state" :class="req.state">{{ req.state }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
|
@ -65,6 +77,7 @@ 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';
|
||||
import follow from '@/directives/follow-append';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -74,6 +87,10 @@ export default defineComponent({
|
|||
MkButton,
|
||||
},
|
||||
|
||||
directives: {
|
||||
follow
|
||||
},
|
||||
|
||||
props: {
|
||||
},
|
||||
|
||||
|
@ -105,6 +122,7 @@ export default defineComponent({
|
|||
return {
|
||||
tab: ref('stream'),
|
||||
popups: os.popups,
|
||||
apiRequests: os.apiRequests,
|
||||
connections,
|
||||
pools,
|
||||
killPopup,
|
||||
|
@ -125,9 +143,7 @@ export default defineComponent({
|
|||
flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
> .windows,
|
||||
> .stream,
|
||||
> .streamPool {
|
||||
> div {
|
||||
display: table;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
|
@ -140,8 +156,31 @@ export default defineComponent({
|
|||
opacity: 0.7;
|
||||
}
|
||||
|
||||
> * {
|
||||
> div {
|
||||
display: table-cell;
|
||||
white-space: nowrap;
|
||||
|
||||
&:not(:last-child) {
|
||||
padding-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.api {
|
||||
> div {
|
||||
> .state {
|
||||
&.pending {
|
||||
color: var(--warn);
|
||||
}
|
||||
|
||||
&.success {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
&.failed {
|
||||
color: var(--error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
25
src/client/directives/follow-append.ts
Normal file
25
src/client/directives/follow-append.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { Directive } from 'vue';
|
||||
import { getScrollContainer, getScrollPosition } from '@/scripts/scroll';
|
||||
|
||||
export default {
|
||||
mounted(src, binding, vn) {
|
||||
const ro = new ResizeObserver((entries, observer) => {
|
||||
const pos = getScrollPosition(src);
|
||||
const container = getScrollContainer(src);
|
||||
const viewHeight = container.clientHeight;
|
||||
const height = container.scrollHeight;
|
||||
if (pos + viewHeight > height - 32) {
|
||||
container.scrollTop = height;
|
||||
}
|
||||
});
|
||||
|
||||
ro.observe(src);
|
||||
|
||||
// TODO: 新たにプロパティを作るのをやめMapを使う
|
||||
src._ro_ = ro;
|
||||
},
|
||||
|
||||
unmounted(src, binding, vn) {
|
||||
src._ro_.unobserve(src);
|
||||
}
|
||||
} as Directive;
|
|
@ -2,7 +2,7 @@ import { Component, defineAsyncComponent, markRaw, reactive, Ref, ref } from 'vu
|
|||
import { EventEmitter } from 'eventemitter3';
|
||||
import Stream from '@/scripts/stream';
|
||||
import { store } from '@/store';
|
||||
import { apiUrl } from '@/config';
|
||||
import { apiUrl, debug } from '@/config';
|
||||
import MkPostFormDialog from '@/components/post-form-dialog.vue';
|
||||
import MkWaitingDialog from '@/components/waiting-dialog.vue';
|
||||
import { resolve } from '@/router';
|
||||
|
@ -13,28 +13,26 @@ export const isMobile = /mobile|iphone|ipad|android/.test(ua);
|
|||
export const stream = markRaw(new Stream());
|
||||
|
||||
export const pendingApiRequestsCount = ref(0);
|
||||
export const apiRequests = ref([]); // for debug
|
||||
|
||||
export const windows = new Map();
|
||||
|
||||
export function api(endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) {
|
||||
pendingApiRequestsCount.value++;
|
||||
|
||||
if (_DEV_) {
|
||||
performance.mark(_PERF_PREFIX_ + 'api:begin');
|
||||
}
|
||||
|
||||
const onFinally = () => {
|
||||
pendingApiRequestsCount.value--;
|
||||
|
||||
if (_DEV_) {
|
||||
performance.mark(_PERF_PREFIX_ + 'api:end');
|
||||
|
||||
performance.measure(_PERF_PREFIX_ + 'api',
|
||||
_PERF_PREFIX_ + 'api:begin',
|
||||
_PERF_PREFIX_ + 'api:end');
|
||||
}
|
||||
};
|
||||
|
||||
const log = debug ? reactive({
|
||||
id: apiRequests.value.length,
|
||||
endpoint,
|
||||
state: 'pending'
|
||||
}) : null;
|
||||
if (debug) {
|
||||
apiRequests.value.push(log);
|
||||
}
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
// Append a credential
|
||||
if (store.getters.isSignedIn) (data as any).i = store.state.i.token;
|
||||
|
@ -51,10 +49,19 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
|
|||
|
||||
if (res.status === 200) {
|
||||
resolve(body);
|
||||
if (debug) {
|
||||
log.state = 'success';
|
||||
}
|
||||
} else if (res.status === 204) {
|
||||
resolve();
|
||||
if (debug) {
|
||||
log.state = 'success';
|
||||
}
|
||||
} else {
|
||||
reject(body.error);
|
||||
if (debug) {
|
||||
log.state = 'failed';
|
||||
}
|
||||
}
|
||||
}).catch(reject);
|
||||
});
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
<MkInput v-model:value="dialogBody">
|
||||
<span>Body</span>
|
||||
</MkInput>
|
||||
<MkRadio v-model="dialogType" value="info">Info</MkRadio>
|
||||
<MkRadio v-model="dialogType" value="success">Success</MkRadio>
|
||||
<MkRadio v-model="dialogType" value="warning">Warn</MkRadio>
|
||||
<MkRadio v-model="dialogType" value="error">Error</MkRadio>
|
||||
<MkSwitch v-model:value="dialogCancel">
|
||||
<span>With cancel button</span>
|
||||
</MkSwitch>
|
||||
|
@ -133,6 +137,7 @@ import MkButton from '@/components/ui/button.vue';
|
|||
import MkInput from '@/components/ui/input.vue';
|
||||
import MkSwitch from '@/components/ui/switch.vue';
|
||||
import MkTextarea from '@/components/ui/textarea.vue';
|
||||
import MkRadio from '@/components/ui/radio.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -141,6 +146,7 @@ export default defineComponent({
|
|||
MkInput,
|
||||
MkSwitch,
|
||||
MkTextarea,
|
||||
MkRadio,
|
||||
},
|
||||
|
||||
data() {
|
||||
|
@ -153,6 +159,7 @@ export default defineComponent({
|
|||
},
|
||||
dialogTitle: 'Hello',
|
||||
dialogBody: 'World!',
|
||||
dialogType: 'info',
|
||||
dialogCancel: false,
|
||||
dialogCancelByBgClick: true,
|
||||
dialogInput: false,
|
||||
|
@ -192,6 +199,7 @@ export default defineComponent({
|
|||
async showDialog() {
|
||||
this.dialogResult = null;
|
||||
this.dialogResult = await os.dialog({
|
||||
type: this.dialogType,
|
||||
title: this.dialogTitle,
|
||||
text: this.dialogBody,
|
||||
showCancelButton: this.dialogCancel,
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
wallpaperOverlay: 'rgba(0, 0, 0, 0.5)',
|
||||
badge: '#31b1ce',
|
||||
messageBg: ':lighten<5<@bg',
|
||||
success: '#86b300',
|
||||
error: '#ec4137',
|
||||
warn: '#ecb637',
|
||||
htmlThemeColor: '@bg',
|
||||
X1: ':alpha<0<@bg',
|
||||
X2: ':darken<2<@panel',
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
wallpaperOverlay: 'rgba(255, 255, 255, 0.5)',
|
||||
badge: '#31b1ce',
|
||||
messageBg: '@panel',
|
||||
success: '#86b300',
|
||||
error: '#ec4137',
|
||||
warn: '#ecb637',
|
||||
htmlThemeColor: '@bg',
|
||||
X1: ':alpha<0<@bg',
|
||||
X2: ':darken<2<@panel',
|
||||
|
|
Loading…
Reference in a new issue