mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-12-23 22:23:10 +02:00
tweak ui
This commit is contained in:
parent
23efba6193
commit
6a5713f5e5
14 changed files with 231 additions and 624 deletions
|
@ -170,10 +170,10 @@ export default defineComponent({
|
||||||
aspectRatio: props.aspectRatio || 2.5,
|
aspectRatio: props.aspectRatio || 2.5,
|
||||||
layout: {
|
layout: {
|
||||||
padding: {
|
padding: {
|
||||||
left: 16,
|
left: 0,
|
||||||
right: 16,
|
right: 0,
|
||||||
top: 16,
|
top: 0,
|
||||||
bottom: 8,
|
bottom: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
scales: {
|
scales: {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-size="{ max: [500] }" v-sticky-container class="vrtktovh _formBlock">
|
<div class="vrtktovh _formBlock">
|
||||||
<div class="label"><slot name="label"></slot></div>
|
<div class="label"><slot name="label"></slot></div>
|
||||||
<div class="main _formRoot">
|
<div class="main _formRoot">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
@ -12,10 +12,8 @@
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.vrtktovh {
|
.vrtktovh {
|
||||||
margin: 0;
|
|
||||||
border-top: solid 0.5px var(--divider);
|
border-top: solid 0.5px var(--divider);
|
||||||
border-bottom: solid 0.5px var(--divider);
|
border-bottom: solid 0.5px var(--divider);
|
||||||
padding: 24px 0;
|
|
||||||
|
|
||||||
& + .vrtktovh {
|
& + .vrtktovh {
|
||||||
border-top: none;
|
border-top: none;
|
||||||
|
@ -31,7 +29,7 @@
|
||||||
|
|
||||||
> .label {
|
> .label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 0 0 16px 0;
|
margin: 1.5em 0 16px 0;
|
||||||
|
|
||||||
&:empty {
|
&:empty {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -39,6 +37,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
> .main {
|
> .main {
|
||||||
|
margin: 1.5em 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -111,7 +111,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
> .label {
|
> .label {
|
||||||
margin-left: 16px;
|
margin-left: 12px;
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
display: block;
|
display: block;
|
||||||
transition: inherit;
|
transition: inherit;
|
||||||
|
|
|
@ -40,7 +40,7 @@ export default defineComponent({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rect.width > props.contentMax || rect.width > 500) {
|
if (rect.width > props.contentMax || (rect.width > 360 && window.innerWidth > 400)) {
|
||||||
margin.value = props.marginMax;
|
margin.value = props.marginMax;
|
||||||
} else {
|
} else {
|
||||||
margin.value = props.marginMin;
|
margin.value = props.marginMin;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="zbcjwnqg" style="margin-top: -8px;">
|
<div class="zbcjwnqg">
|
||||||
<div class="selects" style="display: flex;">
|
<div class="selects" style="display: flex;">
|
||||||
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
|
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
|
||||||
<optgroup :label="$ts.federation">
|
<optgroup :label="$ts.federation">
|
||||||
|
@ -29,16 +29,16 @@
|
||||||
<option value="day">{{ $ts.perDay }}</option>
|
<option value="day">{{ $ts.perDay }}</option>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
</div>
|
</div>
|
||||||
<MkChart :src="chartSrc" :span="chartSpan" :limit="chartLimit" :detailed="detailed"></MkChart>
|
<div class="chart">
|
||||||
|
<MkChart :src="chartSrc" :span="chartSpan" :limit="chartLimit" :detailed="detailed"></MkChart>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onMounted, ref, watch } from 'vue';
|
import { defineComponent, ref } from 'vue';
|
||||||
import MkSelect from '@/components/form/select.vue';
|
import MkSelect from '@/components/form/select.vue';
|
||||||
import MkChart from '@/components/chart.vue';
|
import MkChart from '@/components/chart.vue';
|
||||||
import * as os from '@/os';
|
|
||||||
import { defaultStore } from '@/store';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
@ -74,7 +74,10 @@ export default defineComponent({
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.zbcjwnqg {
|
.zbcjwnqg {
|
||||||
> .selects {
|
> .selects {
|
||||||
padding: 8px 16px 0 16px;
|
}
|
||||||
|
|
||||||
|
> .chart {
|
||||||
|
padding: 8px 0 0 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="alqyeyti">
|
<div class="alqyeyti" :class="{ oneline }">
|
||||||
<div class="key">
|
<div class="key">
|
||||||
<slot name="key"></slot>
|
<slot name="key"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,6 +22,11 @@ export default defineComponent({
|
||||||
required: false,
|
required: false,
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
|
oneline: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
@ -39,10 +44,30 @@ export default defineComponent({
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.alqyeyti {
|
.alqyeyti {
|
||||||
|
> .key, > .value {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
> .key {
|
> .key {
|
||||||
font-size: 0.85em;
|
font-size: 0.85em;
|
||||||
padding: 0 0 0.25em 0;
|
padding: 0 0 0.25em 0;
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.oneline {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
> .key {
|
||||||
|
width: 30%;
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 0 8px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .value {
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -93,7 +93,8 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
[symbols.PAGE_INFO]: {
|
[symbols.PAGE_INFO]: {
|
||||||
title: this.$ts.instanceInfo,
|
title: this.$ts.instanceInfo,
|
||||||
icon: 'fas fa-info-circle'
|
icon: 'fas fa-info-circle',
|
||||||
|
bg: 'var(--bg)',
|
||||||
},
|
},
|
||||||
host,
|
host,
|
||||||
version,
|
version,
|
||||||
|
|
|
@ -1,291 +0,0 @@
|
||||||
<template>
|
|
||||||
<XModalWindow ref="dialog"
|
|
||||||
:width="520"
|
|
||||||
:height="500"
|
|
||||||
@close="$refs.dialog.close()"
|
|
||||||
@closed="$emit('closed')"
|
|
||||||
>
|
|
||||||
<template #header>{{ instance.host }}</template>
|
|
||||||
<div class="mk-instance-info">
|
|
||||||
<div class="_table section">
|
|
||||||
<div class="_row">
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.software }}</div>
|
|
||||||
<div class="_data">{{ instance.softwareName || '?' }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.version }}</div>
|
|
||||||
<div class="_data">{{ instance.softwareVersion || '?' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="_table data section">
|
|
||||||
<div class="_row">
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.registeredAt }}</div>
|
|
||||||
<div class="_data">{{ new Date(instance.caughtAt).toLocaleString() }} (<MkTime :time="instance.caughtAt"/>)</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="_row">
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.following }}</div>
|
|
||||||
<button class="_data _textButton" @click="showFollowing()">{{ number(instance.followingCount) }}</button>
|
|
||||||
</div>
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.followers }}</div>
|
|
||||||
<button class="_data _textButton" @click="showFollowers()">{{ number(instance.followersCount) }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="_row">
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.users }}</div>
|
|
||||||
<button class="_data _textButton" @click="showUsers()">{{ number(instance.usersCount) }}</button>
|
|
||||||
</div>
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.notes }}</div>
|
|
||||||
<div class="_data">{{ number(instance.notesCount) }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="_row">
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.files }}</div>
|
|
||||||
<div class="_data">{{ number(instance.driveFiles) }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.storageUsage }}</div>
|
|
||||||
<div class="_data">{{ bytes(instance.driveUsage) }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="_row">
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.latestRequestSentAt }}</div>
|
|
||||||
<div class="_data"><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></div>
|
|
||||||
</div>
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.latestStatus }}</div>
|
|
||||||
<div class="_data">{{ instance.latestStatus ? instance.latestStatus : 'N/A' }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="_row">
|
|
||||||
<div class="_cell">
|
|
||||||
<div class="_label">{{ $ts.latestRequestReceivedAt }}</div>
|
|
||||||
<div class="_data"><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart">
|
|
||||||
<div class="header">
|
|
||||||
<span class="label">{{ $ts.charts }}</span>
|
|
||||||
<div class="selects">
|
|
||||||
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
|
|
||||||
<option value="instance-requests">{{ $ts._instanceCharts.requests }}</option>
|
|
||||||
<option value="instance-users">{{ $ts._instanceCharts.users }}</option>
|
|
||||||
<option value="instance-users-total">{{ $ts._instanceCharts.usersTotal }}</option>
|
|
||||||
<option value="instance-notes">{{ $ts._instanceCharts.notes }}</option>
|
|
||||||
<option value="instance-notes-total">{{ $ts._instanceCharts.notesTotal }}</option>
|
|
||||||
<option value="instance-ff">{{ $ts._instanceCharts.ff }}</option>
|
|
||||||
<option value="instance-ff-total">{{ $ts._instanceCharts.ffTotal }}</option>
|
|
||||||
<option value="instance-drive-usage">{{ $ts._instanceCharts.cacheSize }}</option>
|
|
||||||
<option value="instance-drive-usage-total">{{ $ts._instanceCharts.cacheSizeTotal }}</option>
|
|
||||||
<option value="instance-drive-files">{{ $ts._instanceCharts.files }}</option>
|
|
||||||
<option value="instance-drive-files-total">{{ $ts._instanceCharts.filesTotal }}</option>
|
|
||||||
</MkSelect>
|
|
||||||
<MkSelect v-model="chartSpan" style="margin: 0;">
|
|
||||||
<option value="hour">{{ $ts.perHour }}</option>
|
|
||||||
<option value="day">{{ $ts.perDay }}</option>
|
|
||||||
</MkSelect>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="chart">
|
|
||||||
<MkChart :src="chartSrc" :span="chartSpan" :limit="90" :detailed="true"></MkChart>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="operations section">
|
|
||||||
<span class="label">{{ $ts.operations }}</span>
|
|
||||||
<MkSwitch v-model="isSuspended" class="switch">{{ $ts.stopActivityDelivery }}</MkSwitch>
|
|
||||||
<MkSwitch :model-value="isBlocked" class="switch" @update:modelValue="changeBlock">{{ $ts.blockThisInstance }}</MkSwitch>
|
|
||||||
<details>
|
|
||||||
<summary>{{ $ts.deleteAllFiles }}</summary>
|
|
||||||
<MkButton style="margin: 0.5em 0 0.5em 0;" @click="deleteAllFiles()"><i class="fas fa-trash-alt"></i> {{ $ts.deleteAllFiles }}</MkButton>
|
|
||||||
</details>
|
|
||||||
<details>
|
|
||||||
<summary>{{ $ts.removeAllFollowing }}</summary>
|
|
||||||
<MkButton style="margin: 0.5em 0 0.5em 0;" @click="removeAllFollowing()"><i class="fas fa-minus-circle"></i> {{ $ts.removeAllFollowing }}</MkButton>
|
|
||||||
<MkInfo warn>{{ $t('removeAllFollowingDescription', { host: instance.host }) }}</MkInfo>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
<details class="metadata section">
|
|
||||||
<summary class="label">{{ $ts.metadata }}</summary>
|
|
||||||
<pre><code>{{ JSON.stringify(instance, null, 2) }}</code></pre>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
</XModalWindow>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, markRaw } from 'vue';
|
|
||||||
import XModalWindow from '@/components/ui/modal-window.vue';
|
|
||||||
import MkSelect from '@/components/form/select.vue';
|
|
||||||
import MkButton from '@/components/ui/button.vue';
|
|
||||||
import MkSwitch from '@/components/form/switch.vue';
|
|
||||||
import MkInfo from '@/components/ui/info.vue';
|
|
||||||
import MkChart from '@/components/chart.vue';
|
|
||||||
import bytes from '@/filters/bytes';
|
|
||||||
import number from '@/filters/number';
|
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
XModalWindow,
|
|
||||||
MkSelect,
|
|
||||||
MkButton,
|
|
||||||
MkSwitch,
|
|
||||||
MkInfo,
|
|
||||||
MkChart,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
instance: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
emits: ['closed'],
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isSuspended: this.instance.isSuspended,
|
|
||||||
chartSrc: 'requests',
|
|
||||||
chartSpan: 'hour',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
meta() {
|
|
||||||
return this.$instance;
|
|
||||||
},
|
|
||||||
|
|
||||||
isBlocked() {
|
|
||||||
return this.meta && this.meta.blockedHosts && this.meta.blockedHosts.includes(this.instance.host);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
isSuspended() {
|
|
||||||
os.api('admin/federation/update-instance', {
|
|
||||||
host: this.instance.host,
|
|
||||||
isSuspended: this.isSuspended
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
changeBlock(e) {
|
|
||||||
os.api('admin/update-meta', {
|
|
||||||
blockedHosts: this.isBlocked ? this.meta.blockedHosts.concat([this.instance.host]) : this.meta.blockedHosts.filter(x => x !== this.instance.host)
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
removeAllFollowing() {
|
|
||||||
os.apiWithDialog('admin/federation/remove-all-following', {
|
|
||||||
host: this.instance.host
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
deleteAllFiles() {
|
|
||||||
os.apiWithDialog('admin/federation/delete-all-files', {
|
|
||||||
host: this.instance.host
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
showFollowing() {
|
|
||||||
// TODO: ページ遷移
|
|
||||||
},
|
|
||||||
|
|
||||||
showFollowers() {
|
|
||||||
// TODO: ページ遷移
|
|
||||||
},
|
|
||||||
|
|
||||||
showUsers() {
|
|
||||||
// TODO: ページ遷移
|
|
||||||
},
|
|
||||||
|
|
||||||
bytes,
|
|
||||||
|
|
||||||
number
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.mk-instance-info {
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
> .section {
|
|
||||||
padding: 16px 32px;
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:first-child) {
|
|
||||||
border-top: solid 0.5px var(--divider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .chart {
|
|
||||||
border-top: solid 0.5px var(--divider);
|
|
||||||
padding: 16px 0 12px 0;
|
|
||||||
|
|
||||||
> .header {
|
|
||||||
padding: 0 32px;
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .label {
|
|
||||||
font-size: 80%;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .selects {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .chart {
|
|
||||||
padding: 0 16px;
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .operations {
|
|
||||||
> .label {
|
|
||||||
font-size: 80%;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .switch {
|
|
||||||
margin: 16px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .metadata {
|
|
||||||
> .label {
|
|
||||||
font-size: 80%;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
> pre > code {
|
|
||||||
display: block;
|
|
||||||
max-height: 200px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -76,7 +76,6 @@ import MkwFederation from '../../widgets/federation.vue';
|
||||||
import { version, url } from '@/config';
|
import { version, url } from '@/config';
|
||||||
import bytes from '@/filters/bytes';
|
import bytes from '@/filters/bytes';
|
||||||
import number from '@/filters/number';
|
import number from '@/filters/number';
|
||||||
import MkInstanceInfo from './instance.vue';
|
|
||||||
|
|
||||||
Chart.register(
|
Chart.register(
|
||||||
ArcElement,
|
ArcElement,
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
<MkContainer :foldable="true" class="charts">
|
<MkContainer :foldable="true" class="charts">
|
||||||
<template #header><i class="fas fa-chart-bar"></i>{{ $ts.charts }}</template>
|
<template #header><i class="fas fa-chart-bar"></i>{{ $ts.charts }}</template>
|
||||||
<div style="padding-top: 12px;">
|
<div style="padding: 12px;">
|
||||||
<MkInstanceStats :chart-limit="500" :detailed="true"/>
|
<MkInstanceStats :chart-limit="500" :detailed="true"/>
|
||||||
</div>
|
</div>
|
||||||
</MkContainer>
|
</MkContainer>
|
||||||
|
@ -77,7 +77,6 @@ import MkQueueChart from '@/components/queue-chart.vue';
|
||||||
import { version, url } from '@/config';
|
import { version, url } from '@/config';
|
||||||
import bytes from '@/filters/bytes';
|
import bytes from '@/filters/bytes';
|
||||||
import number from '@/filters/number';
|
import number from '@/filters/number';
|
||||||
import MkInstanceInfo from './instance.vue';
|
|
||||||
import XMetrics from './metrics.vue';
|
import XMetrics from './metrics.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { stream } from '@/stream';
|
import { stream } from '@/stream';
|
||||||
|
@ -159,9 +158,7 @@ export default defineComponent({
|
||||||
host: q
|
host: q
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
os.popup(MkInstanceInfo, {
|
// TODO
|
||||||
instance: instance
|
|
||||||
}, {}, 'closed');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
bytes,
|
bytes,
|
||||||
|
|
|
@ -1,70 +1,71 @@
|
||||||
<template>
|
<template>
|
||||||
<FormBase>
|
<MkSpacer :content-max="600" :margin-min="16" :margin-max="32">
|
||||||
<FormGroup v-if="instance">
|
<div v-if="instance" class="_formRoot">
|
||||||
<template #label>{{ instance.host }}</template>
|
<div class="fnfelxur">
|
||||||
<FormGroup>
|
<img :src="instance.iconUrl || instance.faviconUrl" alt="" class="icon"/>
|
||||||
<div class="_debobigegoItem">
|
</div>
|
||||||
<div class="_debobigegoPanel fnfelxur">
|
<MkKeyValue :copy="host" oneline style="margin: 1em 0;">
|
||||||
<img :src="instance.iconUrl || instance.faviconUrl" alt="" class="icon"/>
|
<template #key>Host</template>
|
||||||
</div>
|
<template #value><span class="_monospace"><MkLink :url="`https://${host}`">{{ host }}</MkLink></span></template>
|
||||||
</div>
|
</MkKeyValue>
|
||||||
<FormKeyValueView>
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
<template #key>Name</template>
|
<template #key>Name</template>
|
||||||
<template #value><span class="_monospace">{{ instance.name || `(${$ts.unknown})` }}</span></template>
|
<template #value>{{ instance.name || `(${$ts.unknown})` }}</template>
|
||||||
</FormKeyValueView>
|
</MkKeyValue>
|
||||||
</FormGroup>
|
<MkKeyValue>
|
||||||
|
<template #key>{{ $ts.description }}</template>
|
||||||
|
<template #value>{{ instance.description }}</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
|
<template #key>{{ $ts.software }}</template>
|
||||||
|
<template #value><span class="_monospace">{{ instance.softwareName || `(${$ts.unknown})` }} / {{ instance.softwareVersion || `(${$ts.unknown})` }}</span></template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
|
<template #key>{{ $ts.administrator }}</template>
|
||||||
|
<template #value>{{ instance.maintainerName || `(${$ts.unknown})` }} ({{ instance.maintainerEmail || `(${$ts.unknown})` }})</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
|
||||||
<FormButton v-if="$i.isAdmin || $i.isModerator" primary @click="info">{{ $ts.settings }}</FormButton>
|
<FormSection v-if="iAmModerator">
|
||||||
|
<template #label>Moderation</template>
|
||||||
|
<FormSwitch v-model="suspended" class="_formBlock" @update:modelValue="toggleSuspend">{{ $ts.stopActivityDelivery }}</FormSwitch>
|
||||||
|
<FormSwitch :model-value="isBlocked" class="switch" @update:modelValue="changeBlock">{{ $ts.blockThisInstance }}</FormSwitch>
|
||||||
|
</FormSection>
|
||||||
|
|
||||||
<FormTextarea readonly :value="instance.description">
|
<FormSection>
|
||||||
<span>{{ $ts.description }}</span>
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
</FormTextarea>
|
<template #key>{{ $ts.registeredAt }}</template>
|
||||||
|
<template #value><MkTime mode="detail" :time="instance.caughtAt"/></template>
|
||||||
<FormGroup>
|
</MkKeyValue>
|
||||||
<FormKeyValueView>
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
<template #key>{{ $ts.software }}</template>
|
<template #key>{{ $ts.updatedAt }}</template>
|
||||||
<template #value><span class="_monospace">{{ instance.softwareName || `(${$ts.unknown})` }}</span></template>
|
<template #value><MkTime mode="detail" :time="instance.infoUpdatedAt"/></template>
|
||||||
</FormKeyValueView>
|
</MkKeyValue>
|
||||||
<FormKeyValueView>
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
<template #key>{{ $ts.version }}</template>
|
|
||||||
<template #value><span class="_monospace">{{ instance.softwareVersion || `(${$ts.unknown})` }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>{{ $ts.administrator }}</template>
|
|
||||||
<template #value><span class="_monospace">{{ instance.maintainerName || `(${$ts.unknown})` }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>{{ $ts.contact }}</template>
|
|
||||||
<template #value><span class="_monospace">{{ instance.maintainerEmail || `(${$ts.unknown})` }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
<FormGroup>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>{{ $ts.latestRequestSentAt }}</template>
|
<template #key>{{ $ts.latestRequestSentAt }}</template>
|
||||||
<template #value><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></template>
|
<template #value><MkTime v-if="instance.latestRequestSentAt" :time="instance.latestRequestSentAt"/><span v-else>N/A</span></template>
|
||||||
</FormKeyValueView>
|
</MkKeyValue>
|
||||||
<FormKeyValueView>
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
<template #key>{{ $ts.latestStatus }}</template>
|
<template #key>{{ $ts.latestStatus }}</template>
|
||||||
<template #value>{{ instance.latestStatus ? instance.latestStatus : 'N/A' }}</template>
|
<template #value>{{ instance.latestStatus ? instance.latestStatus : 'N/A' }}</template>
|
||||||
</FormKeyValueView>
|
</MkKeyValue>
|
||||||
<FormKeyValueView>
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
<template #key>{{ $ts.latestRequestReceivedAt }}</template>
|
<template #key>{{ $ts.latestRequestReceivedAt }}</template>
|
||||||
<template #value><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></template>
|
<template #value><MkTime v-if="instance.latestRequestReceivedAt" :time="instance.latestRequestReceivedAt"/><span v-else>N/A</span></template>
|
||||||
</FormKeyValueView>
|
</MkKeyValue>
|
||||||
</FormGroup>
|
</FormSection>
|
||||||
<FormGroup>
|
|
||||||
<FormKeyValueView>
|
<FormSection>
|
||||||
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
<template #key>Open Registrations</template>
|
<template #key>Open Registrations</template>
|
||||||
<template #value>{{ instance.openRegistrations ? $ts.yes : $ts.no }}</template>
|
<template #value>{{ instance.openRegistrations ? $ts.yes : $ts.no }}</template>
|
||||||
</FormKeyValueView>
|
</MkKeyValue>
|
||||||
</FormGroup>
|
</FormSection>
|
||||||
<div class="_debobigegoItem">
|
|
||||||
<div class="_debobigegoLabel">{{ $ts.statistics }}</div>
|
<FormSection>
|
||||||
<div class="_debobigegoPanel cmhjzshl">
|
<template #label>{{ $ts.statistics }}</template>
|
||||||
|
<div class="cmhjzshl">
|
||||||
<div class="selects">
|
<div class="selects">
|
||||||
<MkSelect v-model="chartSrc" style="margin: 0; flex: 1;">
|
<MkSelect v-model="chartSrc" style="margin: 0 10px 0 0; flex: 1;">
|
||||||
<option value="instance-requests">{{ $ts._instanceCharts.requests }}</option>
|
<option value="instance-requests">{{ $ts._instanceCharts.requests }}</option>
|
||||||
<option value="instance-users">{{ $ts._instanceCharts.users }}</option>
|
<option value="instance-users">{{ $ts._instanceCharts.users }}</option>
|
||||||
<option value="instance-users-total">{{ $ts._instanceCharts.usersTotal }}</option>
|
<option value="instance-users-total">{{ $ts._instanceCharts.usersTotal }}</option>
|
||||||
|
@ -83,86 +84,56 @@
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
</div>
|
</div>
|
||||||
<div class="chart">
|
<div class="chart">
|
||||||
<MkChart :src="chartSrc" :span="chartSpan" :limit="90" :detailed="true"></MkChart>
|
<MkChart :src="chartSrc" :span="chartSpan" :limit="90" :args="{ host: host }" :detailed="true"></MkChart>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</FormSection>
|
||||||
<FormGroup>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>{{ $ts.registeredAt }}</template>
|
|
||||||
<template #value><MkTime mode="detail" :time="instance.caughtAt"/></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>{{ $ts.updatedAt }}</template>
|
|
||||||
<template #value><MkTime mode="detail" :time="instance.infoUpdatedAt"/></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
<FormObjectView tall :value="instance">
|
<FormObjectView tall :value="instance">
|
||||||
<span>Raw</span>
|
<span>Raw</span>
|
||||||
</FormObjectView>
|
</FormObjectView>
|
||||||
<FormGroup>
|
|
||||||
|
<FormSection>
|
||||||
<template #label>Well-known resources</template>
|
<template #label>Well-known resources</template>
|
||||||
<FormLink :to="`https://${host}/.well-known/host-meta`" external>host-meta</FormLink>
|
<FormLink :to="`https://${host}/.well-known/host-meta`" external style="margin-bottom: 8px;">host-meta</FormLink>
|
||||||
<FormLink :to="`https://${host}/.well-known/host-meta.json`" external>host-meta.json</FormLink>
|
<FormLink :to="`https://${host}/.well-known/host-meta.json`" external style="margin-bottom: 8px;">host-meta.json</FormLink>
|
||||||
<FormLink :to="`https://${host}/.well-known/nodeinfo`" external>nodeinfo</FormLink>
|
<FormLink :to="`https://${host}/.well-known/nodeinfo`" external style="margin-bottom: 8px;">nodeinfo</FormLink>
|
||||||
<FormLink :to="`https://${host}/robots.txt`" external>robots.txt</FormLink>
|
<FormLink :to="`https://${host}/robots.txt`" external style="margin-bottom: 8px;">robots.txt</FormLink>
|
||||||
<FormLink :to="`https://${host}/manifest.json`" external>manifest.json</FormLink>
|
<FormLink :to="`https://${host}/manifest.json`" external style="margin-bottom: 8px;">manifest.json</FormLink>
|
||||||
</FormGroup>
|
</FormSection>
|
||||||
<FormSuspense v-slot="{ result: dns }" :p="dnsPromiseFactory">
|
</div>
|
||||||
<FormGroup>
|
</MkSpacer>
|
||||||
<template #label>DNS</template>
|
|
||||||
<FormKeyValueView v-for="record in dns.a" :key="record">
|
|
||||||
<template #key>A</template>
|
|
||||||
<template #value><span class="_monospace">{{ record }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView v-for="record in dns.aaaa" :key="record">
|
|
||||||
<template #key>AAAA</template>
|
|
||||||
<template #value><span class="_monospace">{{ record }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView v-for="record in dns.cname" :key="record">
|
|
||||||
<template #key>CNAME</template>
|
|
||||||
<template #value><span class="_monospace">{{ record }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView v-for="record in dns.txt">
|
|
||||||
<template #key>TXT</template>
|
|
||||||
<template #value><span class="_monospace">{{ record[0] }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
</FormSuspense>
|
|
||||||
</FormGroup>
|
|
||||||
</FormBase>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||||
import MkChart from '@/components/chart.vue';
|
import MkChart from '@/components/chart.vue';
|
||||||
import FormObjectView from '@/components/debobigego/object-view.vue';
|
import FormObjectView from '@/components/debobigego/object-view.vue';
|
||||||
import FormTextarea from '@/components/debobigego/textarea.vue';
|
import FormTextarea from '@/components/form/textarea.vue';
|
||||||
import FormLink from '@/components/debobigego/link.vue';
|
import FormLink from '@/components/form/link.vue';
|
||||||
import FormBase from '@/components/debobigego/base.vue';
|
import MkLink from '@/components/link.vue';
|
||||||
import FormGroup from '@/components/debobigego/group.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import FormButton from '@/components/debobigego/button.vue';
|
import FormButton from '@/components/ui/button.vue';
|
||||||
import FormKeyValueView from '@/components/debobigego/key-value-view.vue';
|
import MkKeyValue from '@/components/key-value.vue';
|
||||||
import FormSuspense from '@/components/debobigego/suspense.vue';
|
|
||||||
import MkSelect from '@/components/form/select.vue';
|
import MkSelect from '@/components/form/select.vue';
|
||||||
|
import FormSwitch from '@/components/form/switch.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import number from '@/filters/number';
|
import number from '@/filters/number';
|
||||||
import bytes from '@/filters/bytes';
|
import bytes from '@/filters/bytes';
|
||||||
import * as symbols from '@/symbols';
|
import * as symbols from '@/symbols';
|
||||||
import MkInstanceInfo from '@/pages/admin/instance.vue';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
FormBase,
|
|
||||||
FormTextarea,
|
FormTextarea,
|
||||||
FormObjectView,
|
FormObjectView,
|
||||||
FormButton,
|
FormButton,
|
||||||
FormLink,
|
FormLink,
|
||||||
FormGroup,
|
FormSection,
|
||||||
FormKeyValueView,
|
FormSwitch,
|
||||||
FormSuspense,
|
MkKeyValue,
|
||||||
MkSelect,
|
MkSelect,
|
||||||
MkChart,
|
MkChart,
|
||||||
|
MkLink,
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
@ -175,8 +146,9 @@ export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
[symbols.PAGE_INFO]: {
|
[symbols.PAGE_INFO]: {
|
||||||
title: this.$ts.instanceInfo,
|
title: this.host,
|
||||||
icon: 'fas fa-info-circle',
|
icon: 'fas fa-info-circle',
|
||||||
|
bg: 'var(--bg)',
|
||||||
actions: [{
|
actions: [{
|
||||||
text: `https://${this.host}`,
|
text: `https://${this.host}`,
|
||||||
icon: 'fas fa-external-link-alt',
|
icon: 'fas fa-external-link-alt',
|
||||||
|
@ -186,14 +158,22 @@ export default defineComponent({
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
instance: null,
|
instance: null,
|
||||||
dnsPromiseFactory: () => os.api('federation/dns', {
|
suspended: false,
|
||||||
host: this.host
|
|
||||||
}),
|
|
||||||
chartSrc: 'instance-requests',
|
chartSrc: 'instance-requests',
|
||||||
chartSpan: 'hour',
|
chartSpan: 'hour',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
iAmModerator(): boolean {
|
||||||
|
return this.$i && (this.$i.isAdmin || this.$i.isModerator);
|
||||||
|
},
|
||||||
|
|
||||||
|
isBlocked() {
|
||||||
|
return this.instance && this.$instance && this.$instance.blockedHosts && this.$instance.blockedHosts.includes(this.instance.host);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
|
@ -206,24 +186,30 @@ export default defineComponent({
|
||||||
this.instance = await os.api('federation/show-instance', {
|
this.instance = await os.api('federation/show-instance', {
|
||||||
host: this.host
|
host: this.host
|
||||||
});
|
});
|
||||||
|
this.suspended = this.instance.isSuspended;
|
||||||
},
|
},
|
||||||
|
|
||||||
info() {
|
changeBlock(e) {
|
||||||
os.popup(MkInstanceInfo, {
|
os.api('admin/update-meta', {
|
||||||
instance: this.instance
|
blockedHosts: this.isBlocked ? this.meta.blockedHosts.concat([this.instance.host]) : this.meta.blockedHosts.filter(x => x !== this.instance.host)
|
||||||
}, {}, 'closed');
|
});
|
||||||
}
|
},
|
||||||
|
|
||||||
|
async toggleSuspend(v) {
|
||||||
|
await os.api('admin/federation/update-instance', {
|
||||||
|
host: this.instance.host,
|
||||||
|
isSuspended: this.suspended
|
||||||
|
});
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.fnfelxur {
|
.fnfelxur {
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
> .icon {
|
> .icon {
|
||||||
display: block;
|
display: block;
|
||||||
margin: auto;
|
margin: 0;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +218,7 @@ export default defineComponent({
|
||||||
.cmhjzshl {
|
.cmhjzshl {
|
||||||
> .selects {
|
> .selects {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 16px;
|
margin: 0 0 16px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
<template>
|
|
||||||
<FormBase>
|
|
||||||
<FormSuspense v-slot="{ result: ap }" :p="apPromiseFactory">
|
|
||||||
<FormGroup>
|
|
||||||
<template #label>ActivityPub</template>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>Type</template>
|
|
||||||
<template #value><span class="_monospace">{{ ap.type }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>URI</template>
|
|
||||||
<template #value><span class="_monospace">{{ ap.id }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>URL</template>
|
|
||||||
<template #value><span class="_monospace">{{ ap.url }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormGroup>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>Inbox</template>
|
|
||||||
<template #value><span class="_monospace">{{ ap.inbox }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>Shared Inbox</template>
|
|
||||||
<template #value><span class="_monospace">{{ ap.sharedInbox || ap.endpoints.sharedInbox }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>Outbox</template>
|
|
||||||
<template #value><span class="_monospace">{{ ap.outbox }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
<FormTextarea readonly tall code pre :value="ap.publicKey.publicKeyPem">
|
|
||||||
<span>Public Key</span>
|
|
||||||
</FormTextarea>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>Discoverable</template>
|
|
||||||
<template #value>{{ ap.discoverable ? $ts.yes : $ts.no }}</template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>ManuallyApprovesFollowers</template>
|
|
||||||
<template #value>{{ ap.manuallyApprovesFollowers ? $ts.yes : $ts.no }}</template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
<FormObjectView tall :value="ap">
|
|
||||||
<span>Raw</span>
|
|
||||||
</FormObjectView>
|
|
||||||
<FormGroup>
|
|
||||||
<FormLink :to="`https://${user.host}/.well-known/webfinger?resource=acct:${user.username}`" external>WebFinger</FormLink>
|
|
||||||
</FormGroup>
|
|
||||||
<FormLink v-if="user.host" :to="`/instance-info/${user.host}`">{{ $ts.instanceInfo }}<template #suffix>{{ user.host }}</template></FormLink>
|
|
||||||
<FormKeyValueView v-else>
|
|
||||||
<template #key>{{ $ts.instanceInfo }}</template>
|
|
||||||
<template #value>(Local user)</template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
</FormSuspense>
|
|
||||||
</FormBase>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
|
||||||
import FormObjectView from '@/components/debobigego/object-view.vue';
|
|
||||||
import FormTextarea from '@/components/debobigego/textarea.vue';
|
|
||||||
import FormLink from '@/components/debobigego/link.vue';
|
|
||||||
import FormBase from '@/components/debobigego/base.vue';
|
|
||||||
import FormGroup from '@/components/debobigego/group.vue';
|
|
||||||
import FormButton from '@/components/debobigego/button.vue';
|
|
||||||
import FormKeyValueView from '@/components/debobigego/key-value-view.vue';
|
|
||||||
import FormSuspense from '@/components/debobigego/suspense.vue';
|
|
||||||
import * as os from '@/os';
|
|
||||||
import number from '@/filters/number';
|
|
||||||
import bytes from '@/filters/bytes';
|
|
||||||
import * as symbols from '@/symbols';
|
|
||||||
import { url } from '@/config';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
FormBase,
|
|
||||||
FormTextarea,
|
|
||||||
FormObjectView,
|
|
||||||
FormButton,
|
|
||||||
FormLink,
|
|
||||||
FormGroup,
|
|
||||||
FormKeyValueView,
|
|
||||||
FormSuspense,
|
|
||||||
},
|
|
||||||
|
|
||||||
props: {
|
|
||||||
userId: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
[symbols.PAGE_INFO]: {
|
|
||||||
title: this.$ts.userInfo,
|
|
||||||
icon: 'fas fa-info-circle'
|
|
||||||
},
|
|
||||||
user: null,
|
|
||||||
apPromiseFactory: null,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
|
||||||
this.fetch();
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
number,
|
|
||||||
bytes,
|
|
||||||
|
|
||||||
async fetch() {
|
|
||||||
this.user = await os.api('users/show', {
|
|
||||||
userId: this.userId
|
|
||||||
});
|
|
||||||
|
|
||||||
this.apPromiseFactory = () => os.api('ap/get', {
|
|
||||||
uri: this.user.uri || `${url}/users/${this.user.id}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
|
@ -1,70 +1,76 @@
|
||||||
<template>
|
<template>
|
||||||
<FormBase>
|
<MkSpacer :content-max="500" :margin-min="16" :margin-max="32">
|
||||||
<FormSuspense :p="init">
|
<FormSuspense :p="init">
|
||||||
<div class="_debobigegoItem aeakzknw">
|
<div class="_formRoot">
|
||||||
<MkAvatar class="avatar" :user="user" :show-indicator="true"/>
|
<div class="_formBlock aeakzknw">
|
||||||
|
<MkAvatar class="avatar" :user="user" :show-indicator="true"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormLink :to="userPage(user)">Profile</FormLink>
|
||||||
|
|
||||||
|
<div class="_formBlock">
|
||||||
|
<MkKeyValue :copy="acct(user)" oneline style="margin: 1em 0;">
|
||||||
|
<template #key>Acct</template>
|
||||||
|
<template #value><span class="_monospace">{{ acct(user) }}</span></template>
|
||||||
|
</MkKeyValue>
|
||||||
|
|
||||||
|
<MkKeyValue :copy="user.id" oneline style="margin: 1em 0;">
|
||||||
|
<template #key>ID</template>
|
||||||
|
<template #value><span class="_monospace">{{ user.id }}</span></template>
|
||||||
|
</MkKeyValue>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormSection v-if="iAmModerator">
|
||||||
|
<template #label>Moderation</template>
|
||||||
|
<FormSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" v-model="moderator" class="_formBlock" @update:modelValue="toggleModerator">{{ $ts.moderator }}</FormSwitch>
|
||||||
|
<FormSwitch v-model="silenced" class="_formBlock" @update:modelValue="toggleSilence">{{ $ts.silence }}</FormSwitch>
|
||||||
|
<FormSwitch v-model="suspended" class="_formBlock" @update:modelValue="toggleSuspend">{{ $ts.suspend }}</FormSwitch>
|
||||||
|
<FormButton v-if="user.host == null && iAmModerator" class="_formBlock" @click="resetPassword"><i class="fas fa-key"></i> {{ $ts.resetPassword }}</FormButton>
|
||||||
|
</FormSection>
|
||||||
|
|
||||||
|
<FormSection>
|
||||||
|
<template #label>ActivityPub</template>
|
||||||
|
|
||||||
|
<div class="_formBlock">
|
||||||
|
<MkKeyValue v-if="user.host" oneline style="margin: 1em 0;">
|
||||||
|
<template #key>{{ $ts.instanceInfo }}</template>
|
||||||
|
<template #value><MkA :to="`/instance-info/${user.host}`" class="_link">{{ user.host }} <i class="fas fa-angle-right"></i></MkA></template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue v-else oneline style="margin: 1em 0;">
|
||||||
|
<template #key>{{ $ts.instanceInfo }}</template>
|
||||||
|
<template #value>(Local user)</template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue oneline style="margin: 1em 0;">
|
||||||
|
<template #key>{{ $ts.updatedAt }}</template>
|
||||||
|
<template #value><MkTime v-if="user.lastFetchedAt" mode="detail" :time="user.lastFetchedAt"/><span v-else>N/A</span></template>
|
||||||
|
</MkKeyValue>
|
||||||
|
<MkKeyValue v-if="ap" oneline style="margin: 1em 0;">
|
||||||
|
<template #key>Type</template>
|
||||||
|
<template #value><span class="_monospace">{{ ap.type }}</span></template>
|
||||||
|
</MkKeyValue>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormButton v-if="user.host != null" class="_formBlock" @click="updateRemoteUser"><i class="fas fa-sync"></i> {{ $ts.updateRemoteUser }}</FormButton>
|
||||||
|
</FormSection>
|
||||||
|
|
||||||
|
<FormObjectView tall :value="user">
|
||||||
|
<span>Raw</span>
|
||||||
|
</FormObjectView>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<FormLink :to="userPage(user)">Profile</FormLink>
|
|
||||||
|
|
||||||
<FormGroup>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>Acct</template>
|
|
||||||
<template #value><span class="_monospace">{{ acct(user) }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>ID</template>
|
|
||||||
<template #value><span class="_monospace">{{ user.id }}</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup v-if="iAmModerator">
|
|
||||||
<FormSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" v-model="moderator" @update:modelValue="toggleModerator">{{ $ts.moderator }}</FormSwitch>
|
|
||||||
<FormSwitch v-model="silenced" @update:modelValue="toggleSilence">{{ $ts.silence }}</FormSwitch>
|
|
||||||
<FormSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ $ts.suspend }}</FormSwitch>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup>
|
|
||||||
<FormButton v-if="user.host != null" @click="updateRemoteUser"><i class="fas fa-sync"></i> {{ $ts.updateRemoteUser }}</FormButton>
|
|
||||||
<FormButton v-if="user.host == null && iAmModerator" @click="resetPassword"><i class="fas fa-key"></i> {{ $ts.resetPassword }}</FormButton>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup>
|
|
||||||
<FormLink :to="`/user-ap-info/${user.id}`">ActivityPub</FormLink>
|
|
||||||
|
|
||||||
<FormLink v-if="user.host" :to="`/instance-info/${user.host}`">{{ $ts.instanceInfo }}<template #suffix>{{ user.host }}</template></FormLink>
|
|
||||||
<FormKeyValueView v-else>
|
|
||||||
<template #key>{{ $ts.instanceInfo }}</template>
|
|
||||||
<template #value>(Local user)</template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormGroup>
|
|
||||||
<FormKeyValueView>
|
|
||||||
<template #key>{{ $ts.updatedAt }}</template>
|
|
||||||
<template #value><MkTime v-if="user.lastFetchedAt" mode="detail" :time="user.lastFetchedAt"/><span v-else>N/A</span></template>
|
|
||||||
</FormKeyValueView>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
<FormObjectView tall :value="user">
|
|
||||||
<span>Raw</span>
|
|
||||||
</FormObjectView>
|
|
||||||
</FormSuspense>
|
</FormSuspense>
|
||||||
</FormBase>
|
</MkSpacer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineAsyncComponent, defineComponent } from 'vue';
|
import { computed, defineAsyncComponent, defineComponent } from 'vue';
|
||||||
import FormObjectView from '@/components/debobigego/object-view.vue';
|
import FormObjectView from '@/components/debobigego/object-view.vue';
|
||||||
import FormTextarea from '@/components/debobigego/textarea.vue';
|
import FormTextarea from '@/components/form/textarea.vue';
|
||||||
import FormSwitch from '@/components/debobigego/switch.vue';
|
import FormSwitch from '@/components/form/switch.vue';
|
||||||
import FormLink from '@/components/debobigego/link.vue';
|
import FormLink from '@/components/form/link.vue';
|
||||||
import FormBase from '@/components/debobigego/base.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import FormGroup from '@/components/debobigego/group.vue';
|
import FormButton from '@/components/ui/button.vue';
|
||||||
import FormButton from '@/components/debobigego/button.vue';
|
import MkKeyValue from '@/components/key-value.vue';
|
||||||
import FormKeyValueView from '@/components/debobigego/key-value-view.vue';
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
import FormSuspense from '@/components/debobigego/suspense.vue';
|
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import number from '@/filters/number';
|
import number from '@/filters/number';
|
||||||
import bytes from '@/filters/bytes';
|
import bytes from '@/filters/bytes';
|
||||||
|
@ -74,14 +80,13 @@ import { userPage, acct } from '@/filters/user';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
FormBase,
|
FormSection,
|
||||||
FormTextarea,
|
FormTextarea,
|
||||||
FormSwitch,
|
FormSwitch,
|
||||||
FormObjectView,
|
FormObjectView,
|
||||||
FormButton,
|
FormButton,
|
||||||
FormLink,
|
FormLink,
|
||||||
FormGroup,
|
MkKeyValue,
|
||||||
FormKeyValueView,
|
|
||||||
FormSuspense,
|
FormSuspense,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -97,6 +102,7 @@ export default defineComponent({
|
||||||
[symbols.PAGE_INFO]: computed(() => ({
|
[symbols.PAGE_INFO]: computed(() => ({
|
||||||
title: this.user ? acct(this.user) : this.$ts.userInfo,
|
title: this.user ? acct(this.user) : this.$ts.userInfo,
|
||||||
icon: 'fas fa-info-circle',
|
icon: 'fas fa-info-circle',
|
||||||
|
bg: 'var(--bg)',
|
||||||
actions: this.user ? [this.user.url ? {
|
actions: this.user ? [this.user.url ? {
|
||||||
text: this.user.url,
|
text: this.user.url,
|
||||||
icon: 'fas fa-external-link-alt',
|
icon: 'fas fa-external-link-alt',
|
||||||
|
@ -108,6 +114,7 @@ export default defineComponent({
|
||||||
init: null,
|
init: null,
|
||||||
user: null,
|
user: null,
|
||||||
info: null,
|
info: null,
|
||||||
|
ap: null,
|
||||||
moderator: false,
|
moderator: false,
|
||||||
silenced: false,
|
silenced: false,
|
||||||
suspended: false,
|
suspended: false,
|
||||||
|
@ -126,6 +133,13 @@ export default defineComponent({
|
||||||
this.init = this.createFetcher();
|
this.init = this.createFetcher();
|
||||||
},
|
},
|
||||||
immediate: true
|
immediate: true
|
||||||
|
},
|
||||||
|
user() {
|
||||||
|
os.api('ap/get', {
|
||||||
|
uri: this.user.uri || `${url}/users/${this.user.id}`
|
||||||
|
}).then(res => {
|
||||||
|
this.ap = res;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -234,7 +248,6 @@ export default defineComponent({
|
||||||
.aeakzknw {
|
.aeakzknw {
|
||||||
> .avatar {
|
> .avatar {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0 auto;
|
|
||||||
width: 64px;
|
width: 64px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,6 @@ const defaultRoutes = [
|
||||||
{ path: '/notes/:note', name: 'note', component: page('note'), props: route => ({ noteId: route.params.note }) },
|
{ path: '/notes/:note', name: 'note', component: page('note'), props: route => ({ noteId: route.params.note }) },
|
||||||
{ path: '/tags/:tag', component: page('tag'), props: route => ({ tag: route.params.tag }) },
|
{ path: '/tags/:tag', component: page('tag'), props: route => ({ tag: route.params.tag }) },
|
||||||
{ path: '/user-info/:user', component: page('user-info'), props: route => ({ userId: route.params.user }) },
|
{ path: '/user-info/:user', component: page('user-info'), props: route => ({ userId: route.params.user }) },
|
||||||
{ path: '/user-ap-info/:user', component: page('user-ap-info'), props: route => ({ userId: route.params.user }) },
|
|
||||||
{ path: '/instance-info/:host', component: page('instance-info'), props: route => ({ host: route.params.host }) },
|
{ path: '/instance-info/:host', component: page('instance-info'), props: route => ({ host: route.params.host }) },
|
||||||
{ path: '/games/reversi', component: page('reversi/index') },
|
{ path: '/games/reversi', component: page('reversi/index') },
|
||||||
{ path: '/games/reversi/:gameId', component: page('reversi/game'), props: route => ({ gameId: route.params.gameId }) },
|
{ path: '/games/reversi/:gameId', component: page('reversi/game'), props: route => ({ gameId: route.params.gameId }) },
|
||||||
|
|
Loading…
Reference in a new issue