summaryrefslogtreecommitdiff
path: root/packages/client/src/pages/admin
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2022-06-11 19:31:03 +0900
committerGitHub <noreply@github.com>2022-06-11 19:31:03 +0900
commit182a1bf653ecfbcf76e4530b3077c6252b0d4827 (patch)
tree45d1472747d4cac017e96616f844292f5785ccdd /packages/client/src/pages/admin
parent12.110.1 (diff)
parent12.111.0 (diff)
downloadsharkey-182a1bf653ecfbcf76e4530b3077c6252b0d4827.tar.gz
sharkey-182a1bf653ecfbcf76e4530b3077c6252b0d4827.tar.bz2
sharkey-182a1bf653ecfbcf76e4530b3077c6252b0d4827.zip
Merge pull request #8783 from misskey-dev/develop
Release: 12.111.0
Diffstat (limited to 'packages/client/src/pages/admin')
-rw-r--r--packages/client/src/pages/admin/abuses.vue68
-rw-r--r--packages/client/src/pages/admin/ads.vue144
-rw-r--r--packages/client/src/pages/admin/announcements.vue148
-rw-r--r--packages/client/src/pages/admin/bot-protection.vue89
-rw-r--r--packages/client/src/pages/admin/database.vue31
-rw-r--r--packages/client/src/pages/admin/email-settings.vue161
-rw-r--r--packages/client/src/pages/admin/emoji-edit-dialog.vue116
-rw-r--r--packages/client/src/pages/admin/emojis.vue22
-rw-r--r--packages/client/src/pages/admin/file-dialog.vue86
-rw-r--r--packages/client/src/pages/admin/files.vue4
-rw-r--r--packages/client/src/pages/admin/index.vue539
-rw-r--r--packages/client/src/pages/admin/instance-block.vue58
-rw-r--r--packages/client/src/pages/admin/integrations.discord.vue65
-rw-r--r--packages/client/src/pages/admin/integrations.github.vue65
-rw-r--r--packages/client/src/pages/admin/integrations.twitter.vue63
-rw-r--r--packages/client/src/pages/admin/integrations.vue61
-rw-r--r--packages/client/src/pages/admin/metrics.vue2
-rw-r--r--packages/client/src/pages/admin/object-storage.vue170
-rw-r--r--packages/client/src/pages/admin/other-settings.vue61
-rw-r--r--packages/client/src/pages/admin/overview.vue116
-rw-r--r--packages/client/src/pages/admin/proxy-account.vue83
-rw-r--r--packages/client/src/pages/admin/queue.chart.vue72
-rw-r--r--packages/client/src/pages/admin/queue.vue87
-rw-r--r--packages/client/src/pages/admin/relays.vue117
-rw-r--r--packages/client/src/pages/admin/security.vue71
-rw-r--r--packages/client/src/pages/admin/settings.vue266
26 files changed, 1182 insertions, 1583 deletions
diff --git a/packages/client/src/pages/admin/abuses.vue b/packages/client/src/pages/admin/abuses.vue
index 92f93797ce..e1d0361c0b 100644
--- a/packages/client/src/pages/admin/abuses.vue
+++ b/packages/client/src/pages/admin/abuses.vue
@@ -24,10 +24,10 @@
</div>
<!-- TODO
<div class="inputs" style="display: flex; padding-top: 1.2em;">
- <MkInput v-model="searchUsername" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:modelValue="$refs.reports.reload()">
+ <MkInput v-model="searchUsername" style="margin: 0; flex: 1;" type="text" spellcheck="false">
<span>{{ $ts.username }}</span>
</MkInput>
- <MkInput v-model="searchHost" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:modelValue="$refs.reports.reload()" :disabled="pagination.params().origin === 'local'">
+ <MkInput v-model="searchHost" style="margin: 0; flex: 1;" type="text" spellcheck="false" :disabled="pagination.params().origin === 'local'">
<span>{{ $ts.host }}</span>
</MkInput>
</div>
@@ -41,8 +41,8 @@
</div>
</template>
-<script lang="ts">
-import { computed, defineComponent } from 'vue';
+<script lang="ts" setup>
+import { computed } from 'vue';
import MkInput from '@/components/form/input.vue';
import MkSelect from '@/components/form/select.vue';
@@ -50,45 +50,35 @@ import MkPagination from '@/components/ui/pagination.vue';
import XAbuseReport from '@/components/abuse-report.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkInput,
- MkSelect,
- MkPagination,
- XAbuseReport,
- },
+let reports = $ref<InstanceType<typeof MkPagination>>();
- emits: ['info'],
+let state = $ref('unresolved');
+let reporterOrigin = $ref('combined');
+let targetUserOrigin = $ref('combined');
+let searchUsername = $ref('');
+let searchHost = $ref('');
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.abuseReports,
- icon: 'fas fa-exclamation-circle',
- bg: 'var(--bg)',
- },
- searchUsername: '',
- searchHost: '',
- state: 'unresolved',
- reporterOrigin: 'combined',
- targetUserOrigin: 'combined',
- pagination: {
- endpoint: 'admin/abuse-user-reports' as const,
- limit: 10,
- params: computed(() => ({
- state: this.state,
- reporterOrigin: this.reporterOrigin,
- targetUserOrigin: this.targetUserOrigin,
- })),
- },
- }
- },
+const pagination = {
+ endpoint: 'admin/abuse-user-reports' as const,
+ limit: 10,
+ params: computed(() => ({
+ state,
+ reporterOrigin,
+ targetUserOrigin,
+ })),
+};
- methods: {
- resolved(reportId) {
- this.$refs.reports.removeItem(item => item.id === reportId);
- },
+function resolved(reportId) {
+ reports.removeItem(item => item.id === reportId);
+}
+
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.abuseReports,
+ icon: 'fas fa-exclamation-circle',
+ bg: 'var(--bg)',
}
});
</script>
diff --git a/packages/client/src/pages/admin/ads.vue b/packages/client/src/pages/admin/ads.vue
index 8f164caa99..b18e08db96 100644
--- a/packages/client/src/pages/admin/ads.vue
+++ b/packages/client/src/pages/admin/ads.vue
@@ -7,7 +7,7 @@
<template #label>URL</template>
</MkInput>
<MkInput v-model="ad.imageUrl" class="_formBlock">
- <template #label>{{ $ts.imageUrl }}</template>
+ <template #label>{{ i18n.ts.imageUrl }}</template>
</MkInput>
<FormRadios v-model="ad.place" class="_formBlock">
<template #label>Form</template>
@@ -17,34 +17,34 @@
</FormRadios>
<!--
<div style="margin: 32px 0;">
- {{ $ts.priority }}
- <MkRadio v-model="ad.priority" value="high">{{ $ts.high }}</MkRadio>
- <MkRadio v-model="ad.priority" value="middle">{{ $ts.middle }}</MkRadio>
- <MkRadio v-model="ad.priority" value="low">{{ $ts.low }}</MkRadio>
+ {{ i18n.ts.priority }}
+ <MkRadio v-model="ad.priority" value="high">{{ i18n.ts.high }}</MkRadio>
+ <MkRadio v-model="ad.priority" value="middle">{{ i18n.ts.middle }}</MkRadio>
+ <MkRadio v-model="ad.priority" value="low">{{ i18n.ts.low }}</MkRadio>
</div>
-->
<FormSplit>
<MkInput v-model="ad.ratio" type="number">
- <template #label>{{ $ts.ratio }}</template>
+ <template #label>{{ i18n.ts.ratio }}</template>
</MkInput>
<MkInput v-model="ad.expiresAt" type="date">
- <template #label>{{ $ts.expiration }}</template>
+ <template #label>{{ i18n.ts.expiration }}</template>
</MkInput>
</FormSplit>
<MkTextarea v-model="ad.memo" class="_formBlock">
- <template #label>{{ $ts.memo }}</template>
+ <template #label>{{ i18n.ts.memo }}</template>
</MkTextarea>
<div class="buttons _formBlock">
- <MkButton class="button" inline primary style="margin-right: 12px;" @click="save(ad)"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
- <MkButton class="button" inline danger @click="remove(ad)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
+ <MkButton class="button" inline primary style="margin-right: 12px;" @click="save(ad)"><i class="fas fa-save"></i> {{ i18n.ts.save }}</MkButton>
+ <MkButton class="button" inline danger @click="remove(ad)"><i class="fas fa-trash-alt"></i> {{ i18n.ts.remove }}</MkButton>
</div>
</div>
</div>
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import MkButton from '@/components/ui/button.vue';
import MkInput from '@/components/form/input.vue';
import MkTextarea from '@/components/form/textarea.vue';
@@ -52,81 +52,65 @@ import FormRadios from '@/components/form/radios.vue';
import FormSplit from '@/components/form/split.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkButton,
- MkInput,
- MkTextarea,
- FormRadios,
- FormSplit,
- },
+let ads: any[] = $ref([]);
- emits: ['info'],
+os.api('admin/ad/list').then(adsResponse => {
+ ads = adsResponse;
+});
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.ads,
- icon: 'fas fa-audio-description',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- icon: 'fas fa-plus',
- text: this.$ts.add,
- handler: this.add,
- }],
- },
- ads: [],
- }
- },
+function add() {
+ ads.unshift({
+ id: null,
+ memo: '',
+ place: 'square',
+ priority: 'middle',
+ ratio: 1,
+ url: '',
+ imageUrl: null,
+ expiresAt: null,
+ });
+}
- created() {
- os.api('admin/ad/list').then(ads => {
- this.ads = ads;
+function remove(ad) {
+ os.confirm({
+ type: 'warning',
+ text: i18n.t('removeAreYouSure', { x: ad.url }),
+ }).then(({ canceled }) => {
+ if (canceled) return;
+ ads = ads.filter(x => x !== ad);
+ os.apiWithDialog('admin/ad/delete', {
+ id: ad.id
});
- },
-
- methods: {
- add() {
- this.ads.unshift({
- id: null,
- memo: '',
- place: 'square',
- priority: 'middle',
- ratio: 1,
- url: '',
- imageUrl: null,
- expiresAt: null,
- });
- },
+ });
+}
- remove(ad) {
- os.confirm({
- type: 'warning',
- text: this.$t('removeAreYouSure', { x: ad.url }),
- }).then(({ canceled }) => {
- if (canceled) return;
- this.ads = this.ads.filter(x => x != ad);
- os.apiWithDialog('admin/ad/delete', {
- id: ad.id
- });
- });
- },
+function save(ad) {
+ if (ad.id == null) {
+ os.apiWithDialog('admin/ad/create', {
+ ...ad,
+ expiresAt: new Date(ad.expiresAt).getTime()
+ });
+ } else {
+ os.apiWithDialog('admin/ad/update', {
+ ...ad,
+ expiresAt: new Date(ad.expiresAt).getTime()
+ });
+ }
+}
- save(ad) {
- if (ad.id == null) {
- os.apiWithDialog('admin/ad/create', {
- ...ad,
- expiresAt: new Date(ad.expiresAt).getTime()
- });
- } else {
- os.apiWithDialog('admin/ad/update', {
- ...ad,
- expiresAt: new Date(ad.expiresAt).getTime()
- });
- }
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.ads,
+ icon: 'fas fa-audio-description',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ icon: 'fas fa-plus',
+ text: i18n.ts.add,
+ handler: add,
+ }],
}
});
</script>
diff --git a/packages/client/src/pages/admin/announcements.vue b/packages/client/src/pages/admin/announcements.vue
index a0d720bb29..97774975de 100644
--- a/packages/client/src/pages/admin/announcements.vue
+++ b/packages/client/src/pages/admin/announcements.vue
@@ -3,112 +3,98 @@
<section v-for="announcement in announcements" class="_card _gap announcements">
<div class="_content announcement">
<MkInput v-model="announcement.title">
- <template #label>{{ $ts.title }}</template>
+ <template #label>{{ i18n.ts.title }}</template>
</MkInput>
<MkTextarea v-model="announcement.text">
- <template #label>{{ $ts.text }}</template>
+ <template #label>{{ i18n.ts.text }}</template>
</MkTextarea>
<MkInput v-model="announcement.imageUrl">
- <template #label>{{ $ts.imageUrl }}</template>
+ <template #label>{{ i18n.ts.imageUrl }}</template>
</MkInput>
- <p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p>
+ <p v-if="announcement.reads">{{ i18n.t('nUsersRead', { n: announcement.reads }) }}</p>
<div class="buttons">
- <MkButton class="button" inline primary @click="save(announcement)"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
- <MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
+ <MkButton class="button" inline primary @click="save(announcement)"><i class="fas fa-save"></i> {{ i18n.ts.save }}</MkButton>
+ <MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ i18n.ts.remove }}</MkButton>
</div>
</div>
</section>
</div>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import MkButton from '@/components/ui/button.vue';
import MkInput from '@/components/form/input.vue';
import MkTextarea from '@/components/form/textarea.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkButton,
- MkInput,
- MkTextarea,
- },
+let announcements: any[] = $ref([]);
- emits: ['info'],
+os.api('admin/announcements/list').then(announcementResponse => {
+ announcements = announcementResponse;
+});
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.announcements,
- icon: 'fas fa-broadcast-tower',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- icon: 'fas fa-plus',
- text: this.$ts.add,
- handler: this.add,
- }],
- },
- announcements: [],
- }
- },
+function add() {
+ announcements.unshift({
+ id: null,
+ title: '',
+ text: '',
+ imageUrl: null
+ });
+}
- created() {
- os.api('admin/announcements/list').then(announcements => {
- this.announcements = announcements;
- });
- },
+function remove(announcement) {
+ os.confirm({
+ type: 'warning',
+ text: i18n.t('removeAreYouSure', { x: announcement.title }),
+ }).then(({ canceled }) => {
+ if (canceled) return;
+ announcements = announcements.filter(x => x !== announcement);
+ os.api('admin/announcements/delete', announcement);
+ });
+}
- methods: {
- add() {
- this.announcements.unshift({
- id: null,
- title: '',
- text: '',
- imageUrl: null
+function save(announcement) {
+ if (announcement.id == null) {
+ os.api('admin/announcements/create', announcement).then(() => {
+ os.alert({
+ type: 'success',
+ text: i18n.ts.saved
});
- },
-
- remove(announcement) {
- os.confirm({
- type: 'warning',
- text: this.$t('removeAreYouSure', { x: announcement.title }),
- }).then(({ canceled }) => {
- if (canceled) return;
- this.announcements = this.announcements.filter(x => x != announcement);
- os.api('admin/announcements/delete', announcement);
+ }).catch(err => {
+ os.alert({
+ type: 'error',
+ text: err
});
- },
+ });
+ } else {
+ os.api('admin/announcements/update', announcement).then(() => {
+ os.alert({
+ type: 'success',
+ text: i18n.ts.saved
+ });
+ }).catch(err => {
+ os.alert({
+ type: 'error',
+ text: err
+ });
+ });
+ }
+}
- save(announcement) {
- if (announcement.id == null) {
- os.api('admin/announcements/create', announcement).then(() => {
- os.alert({
- type: 'success',
- text: this.$ts.saved
- });
- }).catch(e => {
- os.alert({
- type: 'error',
- text: e
- });
- });
- } else {
- os.api('admin/announcements/update', announcement).then(() => {
- os.alert({
- type: 'success',
- text: this.$ts.saved
- });
- }).catch(e => {
- os.alert({
- type: 'error',
- text: e
- });
- });
- }
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.announcements,
+ icon: 'fas fa-broadcast-tower',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ icon: 'fas fa-plus',
+ text: i18n.ts.add,
+ handler: add,
+ }],
}
});
</script>
diff --git a/packages/client/src/pages/admin/bot-protection.vue b/packages/client/src/pages/admin/bot-protection.vue
index 5e0cdd96a5..30fee5015a 100644
--- a/packages/client/src/pages/admin/bot-protection.vue
+++ b/packages/client/src/pages/admin/bot-protection.vue
@@ -43,8 +43,8 @@
</div>
</template>
-<script lang="ts">
-import { defineAsyncComponent, defineComponent } from 'vue';
+<script lang="ts" setup>
+import { defineAsyncComponent } from 'vue';
import FormRadios from '@/components/form/radios.vue';
import FormInput from '@/components/form/input.vue';
import FormButton from '@/components/ui/button.vue';
@@ -54,64 +54,39 @@ import * as os from '@/os';
import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
-export default defineComponent({
- components: {
- FormRadios,
- FormInput,
- FormButton,
- FormSuspense,
- FormSlot,
- MkCaptcha: defineAsyncComponent(() => import('@/components/captcha.vue')),
- },
+const MkCaptcha = defineAsyncComponent(() => import('@/components/captcha.vue'));
- emits: ['info'],
+let provider = $ref(null);
+let hcaptchaSiteKey: string | null = $ref(null);
+let hcaptchaSecretKey: string | null = $ref(null);
+let recaptchaSiteKey: string | null = $ref(null);
+let recaptchaSecretKey: string | null = $ref(null);
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.botProtection,
- icon: 'fas fa-shield-alt'
- },
- provider: null,
- enableHcaptcha: false,
- hcaptchaSiteKey: null,
- hcaptchaSecretKey: null,
- enableRecaptcha: false,
- recaptchaSiteKey: null,
- recaptchaSecretKey: null,
- }
- },
+const enableHcaptcha = $computed(() => provider === 'hcaptcha');
+const enableRecaptcha = $computed(() => provider === 'recaptcha');
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.enableHcaptcha = meta.enableHcaptcha;
- this.hcaptchaSiteKey = meta.hcaptchaSiteKey;
- this.hcaptchaSecretKey = meta.hcaptchaSecretKey;
- this.enableRecaptcha = meta.enableRecaptcha;
- this.recaptchaSiteKey = meta.recaptchaSiteKey;
- this.recaptchaSecretKey = meta.recaptchaSecretKey;
+async function init() {
+ const meta = await os.api('admin/meta');
+ enableHcaptcha = meta.enableHcaptcha;
+ hcaptchaSiteKey = meta.hcaptchaSiteKey;
+ hcaptchaSecretKey = meta.hcaptchaSecretKey;
+ enableRecaptcha = meta.enableRecaptcha;
+ recaptchaSiteKey = meta.recaptchaSiteKey;
+ recaptchaSecretKey = meta.recaptchaSecretKey;
- this.provider = this.enableHcaptcha ? 'hcaptcha' : this.enableRecaptcha ? 'recaptcha' : null;
+ provider = enableHcaptcha ? 'hcaptcha' : enableRecaptcha ? 'recaptcha' : null;
+}
- this.$watch(() => this.provider, () => {
- this.enableHcaptcha = this.provider === 'hcaptcha';
- this.enableRecaptcha = this.provider === 'recaptcha';
- });
- },
-
- save() {
- os.apiWithDialog('admin/update-meta', {
- enableHcaptcha: this.enableHcaptcha,
- hcaptchaSiteKey: this.hcaptchaSiteKey,
- hcaptchaSecretKey: this.hcaptchaSecretKey,
- enableRecaptcha: this.enableRecaptcha,
- recaptchaSiteKey: this.recaptchaSiteKey,
- recaptchaSecretKey: this.recaptchaSecretKey,
- }).then(() => {
- fetchInstance();
- });
- }
- }
-});
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ enableHcaptcha,
+ hcaptchaSiteKey,
+ hcaptchaSecretKey,
+ enableRecaptcha,
+ recaptchaSiteKey,
+ recaptchaSecretKey,
+ }).then(() => {
+ fetchInstance();
+ });
+}
</script>
diff --git a/packages/client/src/pages/admin/database.vue b/packages/client/src/pages/admin/database.vue
index 3a835eeafa..d3519922b1 100644
--- a/packages/client/src/pages/admin/database.vue
+++ b/packages/client/src/pages/admin/database.vue
@@ -9,36 +9,23 @@
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormSuspense from '@/components/form/suspense.vue';
import MkKeyValue from '@/components/key-value.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
import bytes from '@/filters/bytes';
import number from '@/filters/number';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- FormSuspense,
- MkKeyValue,
- },
+const databasePromiseFactory = () => os.api('admin/get-table-stats').then(res => Object.entries(res).sort((a, b) => b[1].size - a[1].size));
- emits: ['info'],
-
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.database,
- icon: 'fas fa-database',
- bg: 'var(--bg)',
- },
- databasePromiseFactory: () => os.api('admin/get-table-stats', {}).then(res => Object.entries(res).sort((a, b) => b[1].size - a[1].size)),
- }
- },
-
- methods: {
- bytes, number,
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.database,
+ icon: 'fas fa-database',
+ bg: 'var(--bg)',
}
});
</script>
diff --git a/packages/client/src/pages/admin/email-settings.vue b/packages/client/src/pages/admin/email-settings.vue
index 7df0b6db1c..aa13043193 100644
--- a/packages/client/src/pages/admin/email-settings.vue
+++ b/packages/client/src/pages/admin/email-settings.vue
@@ -3,37 +3,37 @@
<FormSuspense :p="init">
<div class="_formRoot">
<FormSwitch v-model="enableEmail" class="_formBlock">
- <template #label>{{ $ts.enableEmail }}</template>
- <template #caption>{{ $ts.emailConfigInfo }}</template>
+ <template #label>{{ i18n.ts.enableEmail }}</template>
+ <template #caption>{{ i18n.ts.emailConfigInfo }}</template>
</FormSwitch>
<template v-if="enableEmail">
<FormInput v-model="email" type="email" class="_formBlock">
- <template #label>{{ $ts.emailAddress }}</template>
+ <template #label>{{ i18n.ts.emailAddress }}</template>
</FormInput>
<FormSection>
- <template #label>{{ $ts.smtpConfig }}</template>
+ <template #label>{{ i18n.ts.smtpConfig }}</template>
<FormSplit :min-width="280">
<FormInput v-model="smtpHost" class="_formBlock">
- <template #label>{{ $ts.smtpHost }}</template>
+ <template #label>{{ i18n.ts.smtpHost }}</template>
</FormInput>
<FormInput v-model="smtpPort" type="number" class="_formBlock">
- <template #label>{{ $ts.smtpPort }}</template>
+ <template #label>{{ i18n.ts.smtpPort }}</template>
</FormInput>
</FormSplit>
<FormSplit :min-width="280">
<FormInput v-model="smtpUser" class="_formBlock">
- <template #label>{{ $ts.smtpUser }}</template>
+ <template #label>{{ i18n.ts.smtpUser }}</template>
</FormInput>
<FormInput v-model="smtpPass" type="password" class="_formBlock">
- <template #label>{{ $ts.smtpPass }}</template>
+ <template #label>{{ i18n.ts.smtpPass }}</template>
</FormInput>
</FormSplit>
- <FormInfo class="_formBlock">{{ $ts.emptyToDisableSmtpAuth }}</FormInfo>
+ <FormInfo class="_formBlock">{{ i18n.ts.emptyToDisableSmtpAuth }}</FormInfo>
<FormSwitch v-model="smtpSecure" class="_formBlock">
- <template #label>{{ $ts.smtpSecure }}</template>
- <template #caption>{{ $ts.smtpSecureInfo }}</template>
+ <template #label>{{ i18n.ts.smtpSecure }}</template>
+ <template #caption>{{ i18n.ts.smtpSecureInfo }}</template>
</FormSwitch>
</FormSection>
</template>
@@ -42,8 +42,8 @@
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormSwitch from '@/components/form/switch.vue';
import FormInput from '@/components/form/input.vue';
import FormInfo from '@/components/ui/info.vue';
@@ -52,86 +52,71 @@ import FormSplit from '@/components/form/split.vue';
import FormSection from '@/components/form/section.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
-import { fetchInstance } from '@/instance';
+import { fetchInstance, instance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- FormSwitch,
- FormInput,
- FormSplit,
- FormSection,
- FormInfo,
- FormSuspense,
- },
+let enableEmail: boolean = $ref(false);
+let email: any = $ref(null);
+let smtpSecure: boolean = $ref(false);
+let smtpHost: string = $ref('');
+let smtpPort: number = $ref(0);
+let smtpUser: string = $ref('');
+let smtpPass: string = $ref('');
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ enableEmail = meta.enableEmail;
+ email = meta.email;
+ smtpSecure = meta.smtpSecure;
+ smtpHost = meta.smtpHost;
+ smtpPort = meta.smtpPort;
+ smtpUser = meta.smtpUser;
+ smtpPass = meta.smtpPass;
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.emailServer,
- icon: 'fas fa-envelope',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- text: this.$ts.testEmail,
- handler: this.testEmail,
- }, {
- asFullButton: true,
- icon: 'fas fa-check',
- text: this.$ts.save,
- handler: this.save,
- }],
- },
- enableEmail: false,
- email: null,
- smtpSecure: false,
- smtpHost: '',
- smtpPort: 0,
- smtpUser: '',
- smtpPass: '',
- }
- },
+async function testEmail() {
+ const { canceled, result: destination } = await os.inputText({
+ title: i18n.ts.destination,
+ type: 'email',
+ placeholder: instance.maintainerEmail
+ });
+ if (canceled) return;
+ os.apiWithDialog('admin/send-email', {
+ to: destination,
+ subject: 'Test email',
+ text: 'Yo'
+ });
+}
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.enableEmail = meta.enableEmail;
- this.email = meta.email;
- this.smtpSecure = meta.smtpSecure;
- this.smtpHost = meta.smtpHost;
- this.smtpPort = meta.smtpPort;
- this.smtpUser = meta.smtpUser;
- this.smtpPass = meta.smtpPass;
- },
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ enableEmail,
+ email,
+ smtpSecure,
+ smtpHost,
+ smtpPort,
+ smtpUser,
+ smtpPass,
+ }).then(() => {
+ fetchInstance();
+ });
+}
- async testEmail() {
- const { canceled, result: destination } = await os.inputText({
- title: this.$ts.destination,
- type: 'email',
- placeholder: this.$instance.maintainerEmail
- });
- if (canceled) return;
- os.apiWithDialog('admin/send-email', {
- to: destination,
- subject: 'Test email',
- text: 'Yo'
- });
- },
-
- save() {
- os.apiWithDialog('admin/update-meta', {
- enableEmail: this.enableEmail,
- email: this.email,
- smtpSecure: this.smtpSecure,
- smtpHost: this.smtpHost,
- smtpPort: this.smtpPort,
- smtpUser: this.smtpUser,
- smtpPass: this.smtpPass,
- }).then(() => {
- fetchInstance();
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.emailServer,
+ icon: 'fas fa-envelope',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ text: i18n.ts.testEmail,
+ handler: testEmail,
+ }, {
+ asFullButton: true,
+ icon: 'fas fa-check',
+ text: i18n.ts.save,
+ handler: save,
+ }],
}
});
</script>
diff --git a/packages/client/src/pages/admin/emoji-edit-dialog.vue b/packages/client/src/pages/admin/emoji-edit-dialog.vue
index 2e3903426e..d482fa49e6 100644
--- a/packages/client/src/pages/admin/emoji-edit-dialog.vue
+++ b/packages/client/src/pages/admin/emoji-edit-dialog.vue
@@ -27,85 +27,71 @@
</XModalWindow>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import XModalWindow from '@/components/ui/modal-window.vue';
import MkButton from '@/components/ui/button.vue';
import MkInput from '@/components/form/input.vue';
import * as os from '@/os';
import { unique } from '@/scripts/array';
+import { i18n } from '@/i18n';
+import { emojiCategories } from '@/instance';
-export default defineComponent({
- components: {
- XModalWindow,
- MkButton,
- MkInput,
- },
+const props = defineProps<{
+ emoji: any,
+}>();
- props: {
- emoji: {
- required: true,
- }
- },
-
- emits: ['done', 'closed'],
+let dialog = $ref(null);
+let name: string = $ref(props.emoji.name);
+let category: string = $ref(props.emoji.category);
+let aliases: string = $ref(props.emoji.aliases.join(' '));
+let categories: string[] = $ref(emojiCategories);
- data() {
- return {
- name: this.emoji.name,
- category: this.emoji.category,
- aliases: this.emoji.aliases?.join(' '),
- categories: [],
- }
- },
+const emit = defineEmits<{
+ (ev: 'done', v: { deleted?: boolean, updated?: any }): void,
+ (ev: 'closed'): void
+}>();
- created() {
- os.api('meta', { detail: false }).then(({ emojis }) => {
- this.categories = unique(emojis.map((x: any) => x.category || '').filter((x: string) => x !== ''));
- });
- },
+function ok() {
+ update();
+}
- methods: {
- ok() {
- this.update();
- },
+async function update() {
+ await os.apiWithDialog('admin/emoji/update', {
+ id: props.emoji.id,
+ name,
+ category,
+ aliases: aliases.split(' '),
+ });
- async update() {
- await os.apiWithDialog('admin/emoji/update', {
- id: this.emoji.id,
- name: this.name,
- category: this.category,
- aliases: this.aliases.split(' '),
- });
+ emit('done', {
+ updated: {
+ id: props.emoji.id,
+ name,
+ category,
+ aliases: aliases.split(' '),
+ }
+ });
- this.$emit('done', {
- updated: {
- name: this.name,
- category: this.category,
- aliases: this.aliases.split(' '),
- }
- });
- this.$refs.dialog.close();
- },
+ dialog.close();
+}
- async del() {
- const { canceled } = await os.confirm({
- type: 'warning',
- text: this.$t('removeAreYouSure', { x: this.emoji.name }),
- });
- if (canceled) return;
+async function del() {
+ const { canceled } = await os.confirm({
+ type: 'warning',
+ text: i18n.t('removeAreYouSure', { x: name }),
+ });
+ if (canceled) return;
- os.api('admin/emoji/delete', {
- id: this.emoji.id
- }).then(() => {
- this.$emit('done', {
- deleted: true
- });
- this.$refs.dialog.close();
- });
- },
- }
-});
+ os.api('admin/emoji/delete', {
+ id: props.emoji.id
+ }).then(() => {
+ emit('done', {
+ deleted: true
+ });
+ dialog.close();
+ });
+}
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/pages/admin/emojis.vue b/packages/client/src/pages/admin/emojis.vue
index a080ee9c23..8ca5b3d65c 100644
--- a/packages/client/src/pages/admin/emojis.vue
+++ b/packages/client/src/pages/admin/emojis.vue
@@ -63,7 +63,7 @@
</template>
<script lang="ts" setup>
-import { computed, defineComponent, ref, toRef } from 'vue';
+import { computed, defineAsyncComponent, defineComponent, ref, toRef } from 'vue';
import MkButton from '@/components/ui/button.vue';
import MkInput from '@/components/form/input.vue';
import MkPagination from '@/components/ui/pagination.vue';
@@ -130,17 +130,17 @@ const add = async (ev: MouseEvent) => {
};
const edit = (emoji) => {
- os.popup(import('./emoji-edit-dialog.vue'), {
+ os.popup(defineAsyncComponent(() => import('./emoji-edit-dialog.vue')), {
emoji: emoji
}, {
done: result => {
if (result.updated) {
- emojisPaginationComponent.value.replaceItem(item => item.id === emoji.id, {
- ...emoji,
+ emojisPaginationComponent.value.updateItem(result.updated.id, (oldEmoji: any) => ({
+ ...oldEmoji,
...result.updated
- });
+ }));
} else if (result.deleted) {
- emojisPaginationComponent.value.removeItem(item => item.id === emoji.id);
+ emojisPaginationComponent.value.removeItem((item) => item.id === emoji.id);
}
},
}, 'closed');
@@ -159,7 +159,7 @@ const remoteMenu = (emoji, ev: MouseEvent) => {
}, {
text: i18n.ts.import,
icon: 'fas fa-plus',
- action: () => { im(emoji) }
+ action: () => { im(emoji); }
}], ev.currentTarget ?? ev.target);
};
@@ -175,10 +175,10 @@ const menu = (ev: MouseEvent) => {
type: 'info',
text: i18n.ts.exportRequested,
});
- }).catch((e) => {
+ }).catch((err) => {
os.alert({
type: 'error',
- text: e.message,
+ text: err.message,
});
});
}
@@ -195,10 +195,10 @@ const menu = (ev: MouseEvent) => {
type: 'info',
text: i18n.ts.importRequested,
});
- }).catch((e) => {
+ }).catch((err) => {
os.alert({
type: 'error',
- text: e.message,
+ text: err.message,
});
});
}
diff --git a/packages/client/src/pages/admin/file-dialog.vue b/packages/client/src/pages/admin/file-dialog.vue
index 4c33f62399..0765548aab 100644
--- a/packages/client/src/pages/admin/file-dialog.vue
+++ b/packages/client/src/pages/admin/file-dialog.vue
@@ -34,74 +34,52 @@
</XModalWindow>
</template>
-<script lang="ts">
-import { computed, defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import MkButton from '@/components/ui/button.vue';
import MkSwitch from '@/components/form/switch.vue';
import XModalWindow from '@/components/ui/modal-window.vue';
import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue';
import bytes from '@/filters/bytes';
import * as os from '@/os';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkButton,
- MkSwitch,
- XModalWindow,
- MkDriveFileThumbnail,
- },
+let file: any = $ref(null);
+let info: any = $ref(null);
+let isSensitive: boolean = $ref(false);
- props: {
- fileId: {
- required: true,
- }
- },
-
- emits: ['closed'],
-
- data() {
- return {
- file: null,
- info: null,
- isSensitive: false,
- };
- },
+const props = defineProps<{
+ fileId: string,
+}>();
- created() {
- this.fetch();
- },
-
- methods: {
- async fetch() {
- this.file = await os.api('drive/files/show', { fileId: this.fileId });
- this.info = await os.api('admin/drive/show-file', { fileId: this.fileId });
- this.isSensitive = this.file.isSensitive;
- },
+async function fetch() {
+ file = await os.api('drive/files/show', { fileId: props.fileId });
+ info = await os.api('admin/drive/show-file', { fileId: props.fileId });
+ isSensitive = file.isSensitive;
+}
- showUser() {
- os.pageWindow(`/user-info/${this.file.userId}`);
- },
+fetch();
- async del() {
- const { canceled } = await os.confirm({
- type: 'warning',
- text: this.$t('removeAreYouSure', { x: this.file.name }),
- });
- if (canceled) return;
+function showUser() {
+ os.pageWindow(`/user-info/${file.userId}`);
+}
- os.apiWithDialog('drive/files/delete', {
- fileId: this.file.id
- });
- },
+async function del() {
+ const { canceled } = await os.confirm({
+ type: 'warning',
+ text: i18n.t('removeAreYouSure', { x: file.name }),
+ });
+ if (canceled) return;
- async toggleIsSensitive(v) {
- await os.api('drive/files/update', { fileId: this.fileId, isSensitive: v });
- this.isSensitive = v;
- },
+ os.apiWithDialog('drive/files/delete', {
+ fileId: file.id
+ });
+}
- bytes
- }
-});
+async function toggleIsSensitive(v) {
+ await os.api('drive/files/update', { fileId: props.fileId, isSensitive: v });
+ isSensitive = v;
+}
</script>
<style lang="scss" scoped>
diff --git a/packages/client/src/pages/admin/files.vue b/packages/client/src/pages/admin/files.vue
index c62f053092..3cda688698 100644
--- a/packages/client/src/pages/admin/files.vue
+++ b/packages/client/src/pages/admin/files.vue
@@ -55,7 +55,7 @@
</template>
<script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, defineAsyncComponent } from 'vue';
import MkButton from '@/components/ui/button.vue';
import MkInput from '@/components/form/input.vue';
import MkSelect from '@/components/form/select.vue';
@@ -93,7 +93,7 @@ function clear() {
}
function show(file) {
- os.popup(import('./file-dialog.vue'), {
+ os.popup(defineAsyncComponent(() => import('./file-dialog.vue')), {
fileId: file.id
}, {}, 'closed');
}
diff --git a/packages/client/src/pages/admin/index.vue b/packages/client/src/pages/admin/index.vue
index 6b11650f48..9b7fa5678e 100644
--- a/packages/client/src/pages/admin/index.vue
+++ b/packages/client/src/pages/admin/index.vue
@@ -1,6 +1,6 @@
<template>
<div ref="el" class="hiyeyicy" :class="{ wide: !narrow }">
- <div v-if="!narrow || page == null" class="nav">
+ <div v-if="!narrow || initialPage == null" class="nav">
<MkHeader :info="header"></MkHeader>
<MkSpacer :content-max="700" :margin-min="16">
@@ -12,21 +12,21 @@
<MkInfo v-if="noMaintainerInformation" warn class="info">{{ $ts.noMaintainerInformationWarning }} <MkA to="/admin/settings" class="_link">{{ $ts.configure }}</MkA></MkInfo>
<MkInfo v-if="noBotProtection" warn class="info">{{ $ts.noBotProtectionWarning }} <MkA to="/admin/security" class="_link">{{ $ts.configure }}</MkA></MkInfo>
- <MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu>
+ <MkSuperMenu :def="menuDef" :grid="initialPage == null"></MkSuperMenu>
</div>
</MkSpacer>
</div>
- <div class="main">
+ <div v-if="!(narrow && initialPage == null)" class="main">
<MkStickyContainer>
<template #header><MkHeader v-if="childInfo && !childInfo.hideHeader" :info="childInfo"/></template>
- <component :is="component" :ref="el => pageChanged(el)" :key="page" v-bind="pageProps"/>
+ <component :is="component" :ref="el => pageChanged(el)" :key="initialPage" v-bind="pageProps"/>
</MkStickyContainer>
</div>
</div>
</template>
-<script lang="ts">
-import { computed, defineAsyncComponent, defineComponent, isRef, nextTick, onMounted, reactive, ref, watch } from 'vue';
+<script lang="ts" setup>
+import { defineAsyncComponent, nextTick, onMounted, onUnmounted, provide, watch } from 'vue';
import { i18n } from '@/i18n';
import MkSuperMenu from '@/components/ui/super-menu.vue';
import MkInfo from '@/components/ui/info.vue';
@@ -35,292 +35,277 @@ import { instance } from '@/instance';
import * as symbols from '@/symbols';
import * as os from '@/os';
import { lookupUser } from '@/scripts/lookup-user';
+import { MisskeyNavigator } from '@/scripts/navigate';
-export default defineComponent({
- components: {
- MkSuperMenu,
- MkInfo,
- },
+const isEmpty = (x: string | null) => x == null || x === '';
- provide: {
- shouldOmitHeaderTitle: false,
- },
+const nav = new MisskeyNavigator();
- props: {
- initialPage: {
- type: String,
- required: false
- }
- },
+const indexInfo = {
+ title: i18n.ts.controlPanel,
+ icon: 'fas fa-cog',
+ bg: 'var(--bg)',
+ hideHeader: true,
+};
- setup(props, context) {
- const indexInfo = {
- title: i18n.ts.controlPanel,
- icon: 'fas fa-cog',
- bg: 'var(--bg)',
- hideHeader: true,
- };
- const INFO = ref(indexInfo);
- const childInfo = ref(null);
- const page = ref(props.initialPage);
- const narrow = ref(false);
- const view = ref(null);
- const el = ref(null);
- const pageChanged = (page) => {
- if (page == null) return;
- const viewInfo = page[symbols.PAGE_INFO];
- if (isRef(viewInfo)) {
- watch(viewInfo, () => {
- childInfo.value = viewInfo.value;
- }, { immediate: true });
- } else {
- childInfo.value = viewInfo;
- }
- };
- const pageProps = ref({});
+const props = defineProps<{
+ initialPage?: string,
+}>();
- const isEmpty = (x: any) => x == null || x == '';
+provide('shouldOmitHeaderTitle', false);
- const noMaintainerInformation = ref(false);
- const noBotProtection = ref(false);
+let INFO = $ref(indexInfo);
+let childInfo = $ref(null);
+let page = $ref(props.initialPage);
+let narrow = $ref(false);
+let view = $ref(null);
+let el = $ref(null);
+let pageProps = $ref({});
+let noMaintainerInformation = isEmpty(instance.maintainerName) || isEmpty(instance.maintainerEmail);
+let noBotProtection = !instance.enableHcaptcha && !instance.enableRecaptcha;
- os.api('meta', { detail: true }).then(meta => {
- // TODO: 設定が完了しても残ったままになるので、ストリーミングでmeta更新イベントを受け取ってよしなに更新する
- noMaintainerInformation.value = isEmpty(meta.maintainerName) || isEmpty(meta.maintainerEmail);
- noBotProtection.value = !meta.enableHcaptcha && !meta.enableRecaptcha;
- });
+const NARROW_THRESHOLD = 600;
+const ro = new ResizeObserver((entries, observer) => {
+ if (entries.length === 0) return;
+ narrow = entries[0].borderBoxSize[0].inlineSize < NARROW_THRESHOLD;
+});
- const menuDef = computed(() => [{
- title: i18n.ts.quickAction,
- items: [{
- type: 'button',
- icon: 'fas fa-search',
- text: i18n.ts.lookup,
- action: lookup,
- }, ...(instance.disableRegistration ? [{
- type: 'button',
- icon: 'fas fa-user',
- text: i18n.ts.invite,
- action: invite,
- }] : [])],
- }, {
- title: i18n.ts.administration,
- items: [{
- icon: 'fas fa-tachometer-alt',
- text: i18n.ts.dashboard,
- to: '/admin/overview',
- active: page.value === 'overview',
- }, {
- icon: 'fas fa-users',
- text: i18n.ts.users,
- to: '/admin/users',
- active: page.value === 'users',
- }, {
- icon: 'fas fa-laugh',
- text: i18n.ts.customEmojis,
- to: '/admin/emojis',
- active: page.value === 'emojis',
- }, {
- icon: 'fas fa-globe',
- text: i18n.ts.federation,
- to: '/admin/federation',
- active: page.value === 'federation',
- }, {
- icon: 'fas fa-clipboard-list',
- text: i18n.ts.jobQueue,
- to: '/admin/queue',
- active: page.value === 'queue',
- }, {
- icon: 'fas fa-cloud',
- text: i18n.ts.files,
- to: '/admin/files',
- active: page.value === 'files',
- }, {
- icon: 'fas fa-broadcast-tower',
- text: i18n.ts.announcements,
- to: '/admin/announcements',
- active: page.value === 'announcements',
- }, {
- icon: 'fas fa-audio-description',
- text: i18n.ts.ads,
- to: '/admin/ads',
- active: page.value === 'ads',
- }, {
- icon: 'fas fa-exclamation-circle',
- text: i18n.ts.abuseReports,
- to: '/admin/abuses',
- active: page.value === 'abuses',
- }],
- }, {
- title: i18n.ts.settings,
- items: [{
- icon: 'fas fa-cog',
- text: i18n.ts.general,
- to: '/admin/settings',
- active: page.value === 'settings',
- }, {
- icon: 'fas fa-envelope',
- text: i18n.ts.emailServer,
- to: '/admin/email-settings',
- active: page.value === 'email-settings',
- }, {
- icon: 'fas fa-cloud',
- text: i18n.ts.objectStorage,
- to: '/admin/object-storage',
- active: page.value === 'object-storage',
- }, {
- icon: 'fas fa-lock',
- text: i18n.ts.security,
- to: '/admin/security',
- active: page.value === 'security',
- }, {
- icon: 'fas fa-globe',
- text: i18n.ts.relays,
- to: '/admin/relays',
- active: page.value === 'relays',
- }, {
- icon: 'fas fa-share-alt',
- text: i18n.ts.integration,
- to: '/admin/integrations',
- active: page.value === 'integrations',
- }, {
- icon: 'fas fa-ban',
- text: i18n.ts.instanceBlocking,
- to: '/admin/instance-block',
- active: page.value === 'instance-block',
- }, {
- icon: 'fas fa-ghost',
- text: i18n.ts.proxyAccount,
- to: '/admin/proxy-account',
- active: page.value === 'proxy-account',
- }, {
- icon: 'fas fa-cogs',
- text: i18n.ts.other,
- to: '/admin/other-settings',
- active: page.value === 'other-settings',
- }],
- }, {
- title: i18n.ts.info,
- items: [{
- icon: 'fas fa-database',
- text: i18n.ts.database,
- to: '/admin/database',
- active: page.value === 'database',
- }],
- }]);
- const component = computed(() => {
- if (page.value == null) return null;
- switch (page.value) {
- case 'overview': return defineAsyncComponent(() => import('./overview.vue'));
- case 'users': return defineAsyncComponent(() => import('./users.vue'));
- case 'emojis': return defineAsyncComponent(() => import('./emojis.vue'));
- case 'federation': return defineAsyncComponent(() => import('../federation.vue'));
- case 'queue': return defineAsyncComponent(() => import('./queue.vue'));
- case 'files': return defineAsyncComponent(() => import('./files.vue'));
- case 'announcements': return defineAsyncComponent(() => import('./announcements.vue'));
- case 'ads': return defineAsyncComponent(() => import('./ads.vue'));
- case 'database': return defineAsyncComponent(() => import('./database.vue'));
- case 'abuses': return defineAsyncComponent(() => import('./abuses.vue'));
- case 'settings': return defineAsyncComponent(() => import('./settings.vue'));
- case 'email-settings': return defineAsyncComponent(() => import('./email-settings.vue'));
- case 'object-storage': return defineAsyncComponent(() => import('./object-storage.vue'));
- case 'security': return defineAsyncComponent(() => import('./security.vue'));
- case 'relays': return defineAsyncComponent(() => import('./relays.vue'));
- case 'integrations': return defineAsyncComponent(() => import('./integrations.vue'));
- case 'instance-block': return defineAsyncComponent(() => import('./instance-block.vue'));
- case 'proxy-account': return defineAsyncComponent(() => import('./proxy-account.vue'));
- case 'other-settings': return defineAsyncComponent(() => import('./other-settings.vue'));
- }
- });
+const menuDef = $computed(() => [{
+ title: i18n.ts.quickAction,
+ items: [{
+ type: 'button',
+ icon: 'fas fa-search',
+ text: i18n.ts.lookup,
+ action: lookup,
+ }, ...(instance.disableRegistration ? [{
+ type: 'button',
+ icon: 'fas fa-user',
+ text: i18n.ts.invite,
+ action: invite,
+ }] : [])],
+}, {
+ title: i18n.ts.administration,
+ items: [{
+ icon: 'fas fa-tachometer-alt',
+ text: i18n.ts.dashboard,
+ to: '/admin/overview',
+ active: props.initialPage === 'overview',
+ }, {
+ icon: 'fas fa-users',
+ text: i18n.ts.users,
+ to: '/admin/users',
+ active: props.initialPage === 'users',
+ }, {
+ icon: 'fas fa-laugh',
+ text: i18n.ts.customEmojis,
+ to: '/admin/emojis',
+ active: props.initialPage === 'emojis',
+ }, {
+ icon: 'fas fa-globe',
+ text: i18n.ts.federation,
+ to: '/admin/federation',
+ active: props.initialPage === 'federation',
+ }, {
+ icon: 'fas fa-clipboard-list',
+ text: i18n.ts.jobQueue,
+ to: '/admin/queue',
+ active: props.initialPage === 'queue',
+ }, {
+ icon: 'fas fa-cloud',
+ text: i18n.ts.files,
+ to: '/admin/files',
+ active: props.initialPage === 'files',
+ }, {
+ icon: 'fas fa-broadcast-tower',
+ text: i18n.ts.announcements,
+ to: '/admin/announcements',
+ active: props.initialPage === 'announcements',
+ }, {
+ icon: 'fas fa-audio-description',
+ text: i18n.ts.ads,
+ to: '/admin/ads',
+ active: props.initialPage === 'ads',
+ }, {
+ icon: 'fas fa-exclamation-circle',
+ text: i18n.ts.abuseReports,
+ to: '/admin/abuses',
+ active: props.initialPage === 'abuses',
+ }],
+}, {
+ title: i18n.ts.settings,
+ items: [{
+ icon: 'fas fa-cog',
+ text: i18n.ts.general,
+ to: '/admin/settings',
+ active: props.initialPage === 'settings',
+ }, {
+ icon: 'fas fa-envelope',
+ text: i18n.ts.emailServer,
+ to: '/admin/email-settings',
+ active: props.initialPage === 'email-settings',
+ }, {
+ icon: 'fas fa-cloud',
+ text: i18n.ts.objectStorage,
+ to: '/admin/object-storage',
+ active: props.initialPage === 'object-storage',
+ }, {
+ icon: 'fas fa-lock',
+ text: i18n.ts.security,
+ to: '/admin/security',
+ active: props.initialPage === 'security',
+ }, {
+ icon: 'fas fa-globe',
+ text: i18n.ts.relays,
+ to: '/admin/relays',
+ active: props.initialPage === 'relays',
+ }, {
+ icon: 'fas fa-share-alt',
+ text: i18n.ts.integration,
+ to: '/admin/integrations',
+ active: props.initialPage === 'integrations',
+ }, {
+ icon: 'fas fa-ban',
+ text: i18n.ts.instanceBlocking,
+ to: '/admin/instance-block',
+ active: props.initialPage === 'instance-block',
+ }, {
+ icon: 'fas fa-ghost',
+ text: i18n.ts.proxyAccount,
+ to: '/admin/proxy-account',
+ active: props.initialPage === 'proxy-account',
+ }, {
+ icon: 'fas fa-cogs',
+ text: i18n.ts.other,
+ to: '/admin/other-settings',
+ active: props.initialPage === 'other-settings',
+ }],
+}, {
+ title: i18n.ts.info,
+ items: [{
+ icon: 'fas fa-database',
+ text: i18n.ts.database,
+ to: '/admin/database',
+ active: props.initialPage === 'database',
+ }],
+}]);
- watch(component, () => {
- pageProps.value = {};
+const component = $computed(() => {
+ if (props.initialPage == null) return null;
+ switch (props.initialPage) {
+ case 'overview': return defineAsyncComponent(() => import('./overview.vue'));
+ case 'users': return defineAsyncComponent(() => import('./users.vue'));
+ case 'emojis': return defineAsyncComponent(() => import('./emojis.vue'));
+ case 'federation': return defineAsyncComponent(() => import('../federation.vue'));
+ case 'queue': return defineAsyncComponent(() => import('./queue.vue'));
+ case 'files': return defineAsyncComponent(() => import('./files.vue'));
+ case 'announcements': return defineAsyncComponent(() => import('./announcements.vue'));
+ case 'ads': return defineAsyncComponent(() => import('./ads.vue'));
+ case 'database': return defineAsyncComponent(() => import('./database.vue'));
+ case 'abuses': return defineAsyncComponent(() => import('./abuses.vue'));
+ case 'settings': return defineAsyncComponent(() => import('./settings.vue'));
+ case 'email-settings': return defineAsyncComponent(() => import('./email-settings.vue'));
+ case 'object-storage': return defineAsyncComponent(() => import('./object-storage.vue'));
+ case 'security': return defineAsyncComponent(() => import('./security.vue'));
+ case 'relays': return defineAsyncComponent(() => import('./relays.vue'));
+ case 'integrations': return defineAsyncComponent(() => import('./integrations.vue'));
+ case 'instance-block': return defineAsyncComponent(() => import('./instance-block.vue'));
+ case 'proxy-account': return defineAsyncComponent(() => import('./proxy-account.vue'));
+ case 'other-settings': return defineAsyncComponent(() => import('./other-settings.vue'));
+ }
+});
- nextTick(() => {
- scroll(el.value, { top: 0 });
- });
- }, { immediate: true });
+watch(component, () => {
+ pageProps = {};
- watch(() => props.initialPage, () => {
- if (props.initialPage == null && !narrow.value) {
- page.value = 'overview';
- } else {
- page.value = props.initialPage;
- if (props.initialPage == null) {
- INFO.value = indexInfo;
- }
- }
- });
+ nextTick(() => {
+ scroll(el, { top: 0 });
+ });
+}, { immediate: true });
- onMounted(() => {
- narrow.value = el.value.offsetWidth < 800;
- if (!narrow.value) {
- page.value = 'overview';
- }
- });
+watch(() => props.initialPage, () => {
+ if (props.initialPage == null && !narrow) {
+ nav.push('/admin/overview');
+ } else {
+ if (props.initialPage == null) {
+ INFO = indexInfo;
+ }
+ }
+});
- const invite = () => {
- os.api('admin/invite').then(x => {
- os.alert({
- type: 'info',
- text: x.code
- });
- }).catch(e => {
- os.alert({
- type: 'error',
- text: e
- });
- });
- };
+watch(narrow, () => {
+ if (props.initialPage == null && !narrow) {
+ nav.push('/admin/overview');
+ }
+});
- const lookup = (ev) => {
- os.popupMenu([{
- text: i18n.ts.user,
- icon: 'fas fa-user',
- action: () => {
- lookupUser();
- }
- }, {
- text: i18n.ts.note,
- icon: 'fas fa-pencil-alt',
- action: () => {
- alert('TODO');
- }
- }, {
- text: i18n.ts.file,
- icon: 'fas fa-cloud',
- action: () => {
- alert('TODO');
- }
- }, {
- text: i18n.ts.instance,
- icon: 'fas fa-globe',
- action: () => {
- alert('TODO');
- }
- }], ev.currentTarget ?? ev.target);
- };
+onMounted(() => {
+ ro.observe(el);
+
+ narrow = el.offsetWidth < NARROW_THRESHOLD;
+ if (props.initialPage == null && !narrow) {
+ nav.push('/admin/overview');
+ }
+});
+
+onUnmounted(() => {
+ ro.disconnect();
+});
+
+const pageChanged = (page) => {
+ if (page == null) {
+ childInfo = null;
+ } else {
+ childInfo = page[symbols.PAGE_INFO];
+ }
+};
- return {
- [symbols.PAGE_INFO]: INFO,
- menuDef,
- header: {
- title: i18n.ts.controlPanel,
- },
- noMaintainerInformation,
- noBotProtection,
- page,
- narrow,
- view,
- el,
- pageChanged,
- childInfo,
- pageProps,
- component,
- invite,
- lookup,
- };
- },
+const invite = () => {
+ os.api('admin/invite').then(x => {
+ os.alert({
+ type: 'info',
+ text: x.code
+ });
+ }).catch(err => {
+ os.alert({
+ type: 'error',
+ text: err,
+ });
+ });
+};
+
+const lookup = (ev) => {
+ os.popupMenu([{
+ text: i18n.ts.user,
+ icon: 'fas fa-user',
+ action: () => {
+ lookupUser();
+ }
+ }, {
+ text: i18n.ts.note,
+ icon: 'fas fa-pencil-alt',
+ action: () => {
+ alert('TODO');
+ }
+ }, {
+ text: i18n.ts.file,
+ icon: 'fas fa-cloud',
+ action: () => {
+ alert('TODO');
+ }
+ }, {
+ text: i18n.ts.instance,
+ icon: 'fas fa-globe',
+ action: () => {
+ alert('TODO');
+ }
+ }], ev.currentTarget ?? ev.target);
+};
+
+defineExpose({
+ [symbols.PAGE_INFO]: INFO,
+ header: {
+ title: i18n.ts.controlPanel,
+ }
});
</script>
diff --git a/packages/client/src/pages/admin/instance-block.vue b/packages/client/src/pages/admin/instance-block.vue
index 4cb8dc604e..3347846a80 100644
--- a/packages/client/src/pages/admin/instance-block.vue
+++ b/packages/client/src/pages/admin/instance-block.vue
@@ -2,57 +2,45 @@
<MkSpacer :content-max="700" :margin-min="16" :margin-max="32">
<FormSuspense :p="init">
<FormTextarea v-model="blockedHosts" class="_formBlock">
- <span>{{ $ts.blockedInstances }}</span>
- <template #caption>{{ $ts.blockedInstancesDescription }}</template>
+ <span>{{ i18n.ts.blockedInstances }}</span>
+ <template #caption>{{ i18n.ts.blockedInstancesDescription }}</template>
</FormTextarea>
- <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+ <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton>
</FormSuspense>
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormButton from '@/components/ui/button.vue';
import FormTextarea from '@/components/form/textarea.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- FormButton,
- FormTextarea,
- FormSuspense,
- },
+let blockedHosts: string = $ref('');
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ blockedHosts = meta.blockedHosts.join('\n');
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.instanceBlocking,
- icon: 'fas fa-ban',
- bg: 'var(--bg)',
- },
- blockedHosts: '',
- }
- },
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ blockedHosts: blockedHosts.split('\n') || [],
+ }).then(() => {
+ fetchInstance();
+ });
+}
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.blockedHosts = meta.blockedHosts.join('\n');
- },
-
- save() {
- os.apiWithDialog('admin/update-meta', {
- blockedHosts: this.blockedHosts.split('\n') || [],
- }).then(() => {
- fetchInstance();
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.instanceBlocking,
+ icon: 'fas fa-ban',
+ bg: 'var(--bg)',
}
});
</script>
diff --git a/packages/client/src/pages/admin/integrations.discord.vue b/packages/client/src/pages/admin/integrations.discord.vue
index 6b50f1b0a9..9fdc51a6ca 100644
--- a/packages/client/src/pages/admin/integrations.discord.vue
+++ b/packages/client/src/pages/admin/integrations.discord.vue
@@ -24,57 +24,36 @@
</FormSuspense>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormSwitch from '@/components/form/switch.vue';
import FormInput from '@/components/form/input.vue';
import FormButton from '@/components/ui/button.vue';
import FormInfo from '@/components/ui/info.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
-import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
-export default defineComponent({
- components: {
- FormSwitch,
- FormInput,
- FormInfo,
- FormButton,
- FormSuspense,
- },
+let uri: string = $ref('');
+let enableDiscordIntegration: boolean = $ref(false);
+let discordClientId: string | null = $ref(null);
+let discordClientSecret: string | null = $ref(null);
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ uri = meta.uri;
+ enableDiscordIntegration = meta.enableDiscordIntegration;
+ discordClientId = meta.discordClientId;
+ discordClientSecret = meta.discordClientSecret;
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: 'Discord',
- icon: 'fab fa-discord'
- },
- enableDiscordIntegration: false,
- discordClientId: null,
- discordClientSecret: null,
- }
- },
-
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.uri = meta.uri;
- this.enableDiscordIntegration = meta.enableDiscordIntegration;
- this.discordClientId = meta.discordClientId;
- this.discordClientSecret = meta.discordClientSecret;
- },
- save() {
- os.apiWithDialog('admin/update-meta', {
- enableDiscordIntegration: this.enableDiscordIntegration,
- discordClientId: this.discordClientId,
- discordClientSecret: this.discordClientSecret,
- }).then(() => {
- fetchInstance();
- });
- }
- }
-});
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ enableDiscordIntegration,
+ discordClientId,
+ discordClientSecret,
+ }).then(() => {
+ fetchInstance();
+ });
+}
</script>
diff --git a/packages/client/src/pages/admin/integrations.github.vue b/packages/client/src/pages/admin/integrations.github.vue
index 67f299e1bc..b10ccb8394 100644
--- a/packages/client/src/pages/admin/integrations.github.vue
+++ b/packages/client/src/pages/admin/integrations.github.vue
@@ -24,57 +24,36 @@
</FormSuspense>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormSwitch from '@/components/form/switch.vue';
import FormInput from '@/components/form/input.vue';
import FormButton from '@/components/ui/button.vue';
import FormInfo from '@/components/ui/info.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
-import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
-export default defineComponent({
- components: {
- FormSwitch,
- FormInput,
- FormInfo,
- FormButton,
- FormSuspense,
- },
+let uri: string = $ref('');
+let enableGithubIntegration: boolean = $ref(false);
+let githubClientId: string | null = $ref(null);
+let githubClientSecret: string | null = $ref(null);
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ uri = meta.uri;
+ enableGithubIntegration = meta.enableGithubIntegration;
+ githubClientId = meta.githubClientId;
+ githubClientSecret = meta.githubClientSecret;
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: 'GitHub',
- icon: 'fab fa-github'
- },
- enableGithubIntegration: false,
- githubClientId: null,
- githubClientSecret: null,
- }
- },
-
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.uri = meta.uri;
- this.enableGithubIntegration = meta.enableGithubIntegration;
- this.githubClientId = meta.githubClientId;
- this.githubClientSecret = meta.githubClientSecret;
- },
- save() {
- os.apiWithDialog('admin/update-meta', {
- enableGithubIntegration: this.enableGithubIntegration,
- githubClientId: this.githubClientId,
- githubClientSecret: this.githubClientSecret,
- }).then(() => {
- fetchInstance();
- });
- }
- }
-});
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ enableGithubIntegration,
+ githubClientId,
+ githubClientSecret,
+ }).then(() => {
+ fetchInstance();
+ });
+}
</script>
diff --git a/packages/client/src/pages/admin/integrations.twitter.vue b/packages/client/src/pages/admin/integrations.twitter.vue
index a389c71506..11b5fd86b2 100644
--- a/packages/client/src/pages/admin/integrations.twitter.vue
+++ b/packages/client/src/pages/admin/integrations.twitter.vue
@@ -24,7 +24,7 @@
</FormSuspense>
</template>
-<script lang="ts">
+<script lang="ts" setup>
import { defineComponent } from 'vue';
import FormSwitch from '@/components/form/switch.vue';
import FormInput from '@/components/form/input.vue';
@@ -32,49 +32,28 @@ import FormButton from '@/components/ui/button.vue';
import FormInfo from '@/components/ui/info.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
-import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
-export default defineComponent({
- components: {
- FormSwitch,
- FormInput,
- FormInfo,
- FormButton,
- FormSuspense,
- },
+let uri: string = $ref('');
+let enableTwitterIntegration: boolean = $ref(false);
+let twitterConsumerKey: string | null = $ref(null);
+let twitterConsumerSecret: string | null = $ref(null);
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ uri = meta.uri;
+ enableTwitterIntegration = meta.enableTwitterIntegration;
+ twitterConsumerKey = meta.twitterConsumerKey;
+ twitterConsumerSecret = meta.twitterConsumerSecret;
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: 'Twitter',
- icon: 'fab fa-twitter'
- },
- enableTwitterIntegration: false,
- twitterConsumerKey: null,
- twitterConsumerSecret: null,
- }
- },
-
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.uri = meta.uri;
- this.enableTwitterIntegration = meta.enableTwitterIntegration;
- this.twitterConsumerKey = meta.twitterConsumerKey;
- this.twitterConsumerSecret = meta.twitterConsumerSecret;
- },
- save() {
- os.apiWithDialog('admin/update-meta', {
- enableTwitterIntegration: this.enableTwitterIntegration,
- twitterConsumerKey: this.twitterConsumerKey,
- twitterConsumerSecret: this.twitterConsumerSecret,
- }).then(() => {
- fetchInstance();
- });
- }
- }
-});
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ enableTwitterIntegration,
+ twitterConsumerKey,
+ twitterConsumerSecret,
+ }).then(() => {
+ fetchInstance();
+ });
+}
</script>
diff --git a/packages/client/src/pages/admin/integrations.vue b/packages/client/src/pages/admin/integrations.vue
index 4db8a9e0a9..d6061d0e51 100644
--- a/packages/client/src/pages/admin/integrations.vue
+++ b/packages/client/src/pages/admin/integrations.vue
@@ -4,69 +4,52 @@
<FormFolder class="_formBlock">
<template #icon><i class="fab fa-twitter"></i></template>
<template #label>Twitter</template>
- <template #suffix>{{ enableTwitterIntegration ? $ts.enabled : $ts.disabled }}</template>
+ <template #suffix>{{ enableTwitterIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template>
<XTwitter/>
</FormFolder>
- <FormFolder to="/admin/integrations/github" class="_formBlock">
+ <FormFolder class="_formBlock">
<template #icon><i class="fab fa-github"></i></template>
<template #label>GitHub</template>
- <template #suffix>{{ enableGithubIntegration ? $ts.enabled : $ts.disabled }}</template>
+ <template #suffix>{{ enableGithubIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template>
<XGithub/>
</FormFolder>
- <FormFolder to="/admin/integrations/discord" class="_formBlock">
+ <FormFolder class="_formBlock">
<template #icon><i class="fab fa-discord"></i></template>
<template #label>Discord</template>
- <template #suffix>{{ enableDiscordIntegration ? $ts.enabled : $ts.disabled }}</template>
+ <template #suffix>{{ enableDiscordIntegration ? i18n.ts.enabled : i18n.ts.disabled }}</template>
<XDiscord/>
</FormFolder>
</FormSuspense>
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormFolder from '@/components/form/folder.vue';
-import FormSecion from '@/components/form/section.vue';
import FormSuspense from '@/components/form/suspense.vue';
import XTwitter from './integrations.twitter.vue';
import XGithub from './integrations.github.vue';
import XDiscord from './integrations.discord.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
-import { fetchInstance } from '@/instance';
-
-export default defineComponent({
- components: {
- FormFolder,
- FormSecion,
- FormSuspense,
- XTwitter,
- XGithub,
- XDiscord,
- },
+import { i18n } from '@/i18n';
- emits: ['info'],
+let enableTwitterIntegration: boolean = $ref(false);
+let enableGithubIntegration: boolean = $ref(false);
+let enableDiscordIntegration: boolean = $ref(false);
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.integration,
- icon: 'fas fa-share-alt',
- bg: 'var(--bg)',
- },
- enableTwitterIntegration: false,
- enableGithubIntegration: false,
- enableDiscordIntegration: false,
- }
- },
+async function init() {
+ const meta = await os.api('admin/meta');
+ enableTwitterIntegration = meta.enableTwitterIntegration;
+ enableGithubIntegration = meta.enableGithubIntegration;
+ enableDiscordIntegration = meta.enableDiscordIntegration;
+}
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.enableTwitterIntegration = meta.enableTwitterIntegration;
- this.enableGithubIntegration = meta.enableGithubIntegration;
- this.enableDiscordIntegration = meta.enableDiscordIntegration;
- },
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.integration,
+ icon: 'fas fa-share-alt',
+ bg: 'var(--bg)',
}
});
</script>
diff --git a/packages/client/src/pages/admin/metrics.vue b/packages/client/src/pages/admin/metrics.vue
index 1de297fd93..7e5f5bb094 100644
--- a/packages/client/src/pages/admin/metrics.vue
+++ b/packages/client/src/pages/admin/metrics.vue
@@ -132,7 +132,7 @@ export default defineComponent({
overviewHeight: '1fr',
queueHeight: '1fr',
paused: false,
- }
+ };
},
computed: {
diff --git a/packages/client/src/pages/admin/object-storage.vue b/packages/client/src/pages/admin/object-storage.vue
index a1ee0761c8..d109db9c38 100644
--- a/packages/client/src/pages/admin/object-storage.vue
+++ b/packages/client/src/pages/admin/object-storage.vue
@@ -2,32 +2,32 @@
<MkSpacer :content-max="700" :margin-min="16" :margin-max="32">
<FormSuspense :p="init">
<div class="_formRoot">
- <FormSwitch v-model="useObjectStorage" class="_formBlock">{{ $ts.useObjectStorage }}</FormSwitch>
+ <FormSwitch v-model="useObjectStorage" class="_formBlock">{{ i18n.ts.useObjectStorage }}</FormSwitch>
<template v-if="useObjectStorage">
<FormInput v-model="objectStorageBaseUrl" class="_formBlock">
- <template #label>{{ $ts.objectStorageBaseUrl }}</template>
- <template #caption>{{ $ts.objectStorageBaseUrlDesc }}</template>
+ <template #label>{{ i18n.ts.objectStorageBaseUrl }}</template>
+ <template #caption>{{ i18n.ts.objectStorageBaseUrlDesc }}</template>
</FormInput>
<FormInput v-model="objectStorageBucket" class="_formBlock">
- <template #label>{{ $ts.objectStorageBucket }}</template>
- <template #caption>{{ $ts.objectStorageBucketDesc }}</template>
+ <template #label>{{ i18n.ts.objectStorageBucket }}</template>
+ <template #caption>{{ i18n.ts.objectStorageBucketDesc }}</template>
</FormInput>
<FormInput v-model="objectStoragePrefix" class="_formBlock">
- <template #label>{{ $ts.objectStoragePrefix }}</template>
- <template #caption>{{ $ts.objectStoragePrefixDesc }}</template>
+ <template #label>{{ i18n.ts.objectStoragePrefix }}</template>
+ <template #caption>{{ i18n.ts.objectStoragePrefixDesc }}</template>
</FormInput>
<FormInput v-model="objectStorageEndpoint" class="_formBlock">
- <template #label>{{ $ts.objectStorageEndpoint }}</template>
- <template #caption>{{ $ts.objectStorageEndpointDesc }}</template>
+ <template #label>{{ i18n.ts.objectStorageEndpoint }}</template>
+ <template #caption>{{ i18n.ts.objectStorageEndpointDesc }}</template>
</FormInput>
<FormInput v-model="objectStorageRegion" class="_formBlock">
- <template #label>{{ $ts.objectStorageRegion }}</template>
- <template #caption>{{ $ts.objectStorageRegionDesc }}</template>
+ <template #label>{{ i18n.ts.objectStorageRegion }}</template>
+ <template #caption>{{ i18n.ts.objectStorageRegionDesc }}</template>
</FormInput>
<FormSplit :min-width="280">
@@ -43,17 +43,17 @@
</FormSplit>
<FormSwitch v-model="objectStorageUseSSL" class="_formBlock">
- <template #label>{{ $ts.objectStorageUseSSL }}</template>
- <template #caption>{{ $ts.objectStorageUseSSLDesc }}</template>
+ <template #label>{{ i18n.ts.objectStorageUseSSL }}</template>
+ <template #caption>{{ i18n.ts.objectStorageUseSSLDesc }}</template>
</FormSwitch>
<FormSwitch v-model="objectStorageUseProxy" class="_formBlock">
- <template #label>{{ $ts.objectStorageUseProxy }}</template>
- <template #caption>{{ $ts.objectStorageUseProxyDesc }}</template>
+ <template #label>{{ i18n.ts.objectStorageUseProxy }}</template>
+ <template #caption>{{ i18n.ts.objectStorageUseProxyDesc }}</template>
</FormSwitch>
<FormSwitch v-model="objectStorageSetPublicRead" class="_formBlock">
- <template #label>{{ $ts.objectStorageSetPublicRead }}</template>
+ <template #label>{{ i18n.ts.objectStorageSetPublicRead }}</template>
</FormSwitch>
<FormSwitch v-model="objectStorageS3ForcePathStyle" class="_formBlock">
@@ -65,8 +65,8 @@
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormSwitch from '@/components/form/switch.vue';
import FormInput from '@/components/form/input.vue';
import FormGroup from '@/components/form/group.vue';
@@ -76,84 +76,70 @@ import FormSection from '@/components/form/section.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- FormSwitch,
- FormInput,
- FormGroup,
- FormSuspense,
- FormSplit,
- FormSection,
- },
+let useObjectStorage: boolean = $ref(false);
+let objectStorageBaseUrl: string | null = $ref(null);
+let objectStorageBucket: string | null = $ref(null);
+let objectStoragePrefix: string | null = $ref(null);
+let objectStorageEndpoint: string | null = $ref(null);
+let objectStorageRegion: string | null = $ref(null);
+let objectStoragePort: number | null = $ref(null);
+let objectStorageAccessKey: string | null = $ref(null);
+let objectStorageSecretKey: string | null = $ref(null);
+let objectStorageUseSSL: boolean = $ref(false);
+let objectStorageUseProxy: boolean = $ref(false);
+let objectStorageSetPublicRead: boolean = $ref(false);
+let objectStorageS3ForcePathStyle: boolean = $ref(true);
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ useObjectStorage = meta.useObjectStorage;
+ objectStorageBaseUrl = meta.objectStorageBaseUrl;
+ objectStorageBucket = meta.objectStorageBucket;
+ objectStoragePrefix = meta.objectStoragePrefix;
+ objectStorageEndpoint = meta.objectStorageEndpoint;
+ objectStorageRegion = meta.objectStorageRegion;
+ objectStoragePort = meta.objectStoragePort;
+ objectStorageAccessKey = meta.objectStorageAccessKey;
+ objectStorageSecretKey = meta.objectStorageSecretKey;
+ objectStorageUseSSL = meta.objectStorageUseSSL;
+ objectStorageUseProxy = meta.objectStorageUseProxy;
+ objectStorageSetPublicRead = meta.objectStorageSetPublicRead;
+ objectStorageS3ForcePathStyle = meta.objectStorageS3ForcePathStyle;
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.objectStorage,
- icon: 'fas fa-cloud',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- icon: 'fas fa-check',
- text: this.$ts.save,
- handler: this.save,
- }],
- },
- useObjectStorage: false,
- objectStorageBaseUrl: null,
- objectStorageBucket: null,
- objectStoragePrefix: null,
- objectStorageEndpoint: null,
- objectStorageRegion: null,
- objectStoragePort: null,
- objectStorageAccessKey: null,
- objectStorageSecretKey: null,
- objectStorageUseSSL: false,
- objectStorageUseProxy: false,
- objectStorageSetPublicRead: false,
- objectStorageS3ForcePathStyle: true,
- }
- },
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ useObjectStorage,
+ objectStorageBaseUrl,
+ objectStorageBucket,
+ objectStoragePrefix,
+ objectStorageEndpoint,
+ objectStorageRegion,
+ objectStoragePort,
+ objectStorageAccessKey,
+ objectStorageSecretKey,
+ objectStorageUseSSL,
+ objectStorageUseProxy,
+ objectStorageSetPublicRead,
+ objectStorageS3ForcePathStyle,
+ }).then(() => {
+ fetchInstance();
+ });
+}
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.useObjectStorage = meta.useObjectStorage;
- this.objectStorageBaseUrl = meta.objectStorageBaseUrl;
- this.objectStorageBucket = meta.objectStorageBucket;
- this.objectStoragePrefix = meta.objectStoragePrefix;
- this.objectStorageEndpoint = meta.objectStorageEndpoint;
- this.objectStorageRegion = meta.objectStorageRegion;
- this.objectStoragePort = meta.objectStoragePort;
- this.objectStorageAccessKey = meta.objectStorageAccessKey;
- this.objectStorageSecretKey = meta.objectStorageSecretKey;
- this.objectStorageUseSSL = meta.objectStorageUseSSL;
- this.objectStorageUseProxy = meta.objectStorageUseProxy;
- this.objectStorageSetPublicRead = meta.objectStorageSetPublicRead;
- this.objectStorageS3ForcePathStyle = meta.objectStorageS3ForcePathStyle;
- },
- save() {
- os.apiWithDialog('admin/update-meta', {
- useObjectStorage: this.useObjectStorage,
- objectStorageBaseUrl: this.objectStorageBaseUrl ? this.objectStorageBaseUrl : null,
- objectStorageBucket: this.objectStorageBucket ? this.objectStorageBucket : null,
- objectStoragePrefix: this.objectStoragePrefix ? this.objectStoragePrefix : null,
- objectStorageEndpoint: this.objectStorageEndpoint ? this.objectStorageEndpoint : null,
- objectStorageRegion: this.objectStorageRegion ? this.objectStorageRegion : null,
- objectStoragePort: this.objectStoragePort ? this.objectStoragePort : null,
- objectStorageAccessKey: this.objectStorageAccessKey ? this.objectStorageAccessKey : null,
- objectStorageSecretKey: this.objectStorageSecretKey ? this.objectStorageSecretKey : null,
- objectStorageUseSSL: this.objectStorageUseSSL,
- objectStorageUseProxy: this.objectStorageUseProxy,
- objectStorageSetPublicRead: this.objectStorageSetPublicRead,
- objectStorageS3ForcePathStyle: this.objectStorageS3ForcePathStyle,
- }).then(() => {
- fetchInstance();
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.objectStorage,
+ icon: 'fas fa-cloud',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ icon: 'fas fa-check',
+ text: i18n.ts.save,
+ handler: save,
+ }],
}
});
</script>
diff --git a/packages/client/src/pages/admin/other-settings.vue b/packages/client/src/pages/admin/other-settings.vue
index 99ea6a5f32..552b05f347 100644
--- a/packages/client/src/pages/admin/other-settings.vue
+++ b/packages/client/src/pages/admin/other-settings.vue
@@ -6,52 +6,35 @@
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
-import FormSwitch from '@/components/form/switch.vue';
-import FormInput from '@/components/form/input.vue';
-import FormSection from '@/components/form/section.vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- FormSwitch,
- FormInput,
- FormSection,
- FormSuspense,
- },
+async function init() {
+ await os.api('admin/meta');
+}
- emits: ['info'],
+function save() {
+ os.apiWithDialog('admin/update-meta').then(() => {
+ fetchInstance();
+ });
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.other,
- icon: 'fas fa-cogs',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- icon: 'fas fa-check',
- text: this.$ts.save,
- handler: this.save,
- }],
- },
- }
- },
-
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- },
- save() {
- os.apiWithDialog('admin/update-meta', {
- }).then(() => {
- fetchInstance();
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.other,
+ icon: 'fas fa-cogs',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ icon: 'fas fa-check',
+ text: i18n.ts.save,
+ handler: save,
+ }],
}
});
</script>
diff --git a/packages/client/src/pages/admin/overview.vue b/packages/client/src/pages/admin/overview.vue
index b8ae8ad9e1..cc69424c3b 100644
--- a/packages/client/src/pages/admin/overview.vue
+++ b/packages/client/src/pages/admin/overview.vue
@@ -5,20 +5,20 @@
<div class="label">Users</div>
<div class="value _monospace">
{{ number(stats.originalUsersCount) }}
- <MkNumberDiff v-if="usersComparedToThePrevDay != null" v-tooltip="$ts.dayOverDayChanges" class="diff" :value="usersComparedToThePrevDay"><template #before>(</template><template #after>)</template></MkNumberDiff>
+ <MkNumberDiff v-if="usersComparedToThePrevDay != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="usersComparedToThePrevDay"><template #before>(</template><template #after>)</template></MkNumberDiff>
</div>
</div>
<div class="number _panel">
<div class="label">Notes</div>
<div class="value _monospace">
{{ number(stats.originalNotesCount) }}
- <MkNumberDiff v-if="notesComparedToThePrevDay != null" v-tooltip="$ts.dayOverDayChanges" class="diff" :value="notesComparedToThePrevDay"><template #before>(</template><template #after>)</template></MkNumberDiff>
+ <MkNumberDiff v-if="notesComparedToThePrevDay != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="notesComparedToThePrevDay"><template #before>(</template><template #after>)</template></MkNumberDiff>
</div>
</div>
</div>
<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>{{ i18n.ts.charts }}</template>
<div style="padding: 12px;">
<MkInstanceStats :chart-limit="500" :detailed="true"/>
</div>
@@ -38,7 +38,7 @@
<!--<XMetrics/>-->
<MkFolder style="margin: var(--margin)">
- <template #header><i class="fas fa-info-circle"></i> {{ $ts.info }}</template>
+ <template #header><i class="fas fa-info-circle"></i> {{ i18n.ts.info }}</template>
<div class="cfcdecdf">
<div class="number _panel">
<div class="label">Misskey</div>
@@ -65,103 +65,61 @@
</div>
</template>
-<script lang="ts">
-import { computed, defineComponent, markRaw, version as vueVersion } from 'vue';
+<script lang="ts" setup>
+import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick } from 'vue';
import MkInstanceStats from '@/components/instance-stats.vue';
-import MkButton from '@/components/ui/button.vue';
-import MkSelect from '@/components/form/select.vue';
import MkNumberDiff from '@/components/number-diff.vue';
import MkContainer from '@/components/ui/container.vue';
import MkFolder from '@/components/ui/folder.vue';
import MkQueueChart from '@/components/queue-chart.vue';
import { version, url } from '@/config';
-import bytes from '@/filters/bytes';
import number from '@/filters/number';
import XMetrics from './metrics.vue';
import * as os from '@/os';
import { stream } from '@/stream';
import * as symbols from '@/symbols';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkNumberDiff,
- MkInstanceStats,
- MkContainer,
- MkFolder,
- MkQueueChart,
- XMetrics,
- },
+let stats: any = $ref(null);
+let serverInfo: any = $ref(null);
+let usersComparedToThePrevDay: any = $ref(null);
+let notesComparedToThePrevDay: any = $ref(null);
+const queueStatsConnection = markRaw(stream.useChannel('queueStats'));
- emits: ['info'],
+onMounted(async () => {
+ os.api('stats', {}).then(statsResponse => {
+ stats = statsResponse;
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.dashboard,
- icon: 'fas fa-tachometer-alt',
- bg: 'var(--bg)',
- },
- version,
- vueVersion,
- url,
- stats: null,
- meta: null,
- serverInfo: null,
- usersComparedToThePrevDay: null,
- notesComparedToThePrevDay: null,
- fetchJobs: () => os.api('admin/queue/deliver-delayed', {}),
- fetchModLogs: () => os.api('admin/show-moderation-logs', {}),
- queueStatsConnection: markRaw(stream.useChannel('queueStats')),
- }
- },
-
- async mounted() {
- os.api('meta', { detail: true }).then(meta => {
- this.meta = meta;
+ os.api('charts/users', { limit: 2, span: 'day' }).then(chart => {
+ usersComparedToThePrevDay = stats.originalUsersCount - chart.local.total[1];
});
-
- os.api('stats', {}).then(stats => {
- this.stats = stats;
-
- os.api('charts/users', { limit: 2, span: 'day' }).then(chart => {
- this.usersComparedToThePrevDay = this.stats.originalUsersCount - chart.local.total[1];
- });
- os.api('charts/notes', { limit: 2, span: 'day' }).then(chart => {
- this.notesComparedToThePrevDay = this.stats.originalNotesCount - chart.local.total[1];
- });
+ os.api('charts/notes', { limit: 2, span: 'day' }).then(chart => {
+ notesComparedToThePrevDay = stats.originalNotesCount - chart.local.total[1];
});
+ });
- os.api('admin/server-info', {}).then(serverInfo => {
- this.serverInfo = serverInfo;
- });
+ os.api('admin/server-info').then(serverInfoResponse => {
+ serverInfo = serverInfoResponse;
+ });
- this.$nextTick(() => {
- this.queueStatsConnection.send('requestLog', {
- id: Math.random().toString().substr(2, 8),
- length: 200
- });
+ nextTick(() => {
+ queueStatsConnection.send('requestLog', {
+ id: Math.random().toString().substr(2, 8),
+ length: 200
});
- },
-
- beforeUnmount() {
- this.queueStatsConnection.dispose();
- },
-
- methods: {
- async showInstanceInfo(q) {
- let instance = q;
- if (typeof q === 'string') {
- instance = await os.api('federation/show-instance', {
- host: q
- });
- }
- // TODO
- },
+ });
+});
- bytes,
+onBeforeUnmount(() => {
+ queueStatsConnection.dispose();
+});
- number,
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.dashboard,
+ icon: 'fas fa-tachometer-alt',
+ bg: 'var(--bg)',
}
});
</script>
diff --git a/packages/client/src/pages/admin/proxy-account.vue b/packages/client/src/pages/admin/proxy-account.vue
index 00f14a176f..727e20e7e5 100644
--- a/packages/client/src/pages/admin/proxy-account.vue
+++ b/packages/client/src/pages/admin/proxy-account.vue
@@ -1,19 +1,19 @@
<template>
<MkSpacer :content-max="700" :margin-min="16" :margin-max="32">
<FormSuspense :p="init">
- <MkInfo class="_formBlock">{{ $ts.proxyAccountDescription }}</MkInfo>
+ <MkInfo class="_formBlock">{{ i18n.ts.proxyAccountDescription }}</MkInfo>
<MkKeyValue class="_formBlock">
- <template #key>{{ $ts.proxyAccount }}</template>
- <template #value>{{ proxyAccount ? `@${proxyAccount.username}` : $ts.none }}</template>
+ <template #key>{{ i18n.ts.proxyAccount }}</template>
+ <template #value>{{ proxyAccount ? `@${proxyAccount.username}` : i18n.ts.none }}</template>
</MkKeyValue>
- <FormButton primary class="_formBlock" @click="chooseProxyAccount">{{ $ts.selectAccount }}</FormButton>
+ <FormButton primary class="_formBlock" @click="chooseProxyAccount">{{ i18n.ts.selectAccount }}</FormButton>
</FormSuspense>
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import MkKeyValue from '@/components/key-value.vue';
import FormButton from '@/components/ui/button.vue';
import MkInfo from '@/components/ui/info.vue';
@@ -21,53 +21,40 @@ import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkKeyValue,
- FormButton,
- MkInfo,
- FormSuspense,
- },
+let proxyAccount: any = $ref(null);
+let proxyAccountId: any = $ref(null);
- emits: ['info'],
-
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.proxyAccount,
- icon: 'fas fa-ghost',
- bg: 'var(--bg)',
- },
- proxyAccount: null,
- proxyAccountId: null,
- }
- },
+async function init() {
+ const meta = await os.api('admin/meta');
+ proxyAccountId = meta.proxyAccountId;
+ if (proxyAccountId) {
+ proxyAccount = await os.api('users/show', { userId: proxyAccountId });
+ }
+}
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.proxyAccountId = meta.proxyAccountId;
- if (this.proxyAccountId) {
- this.proxyAccount = await os.api('users/show', { userId: this.proxyAccountId });
- }
- },
+function chooseProxyAccount() {
+ os.selectUser().then(user => {
+ proxyAccount = user;
+ proxyAccountId = user.id;
+ save();
+ });
+}
- chooseProxyAccount() {
- os.selectUser().then(user => {
- this.proxyAccount = user;
- this.proxyAccountId = user.id;
- this.save();
- });
- },
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ proxyAccountId: proxyAccountId,
+ }).then(() => {
+ fetchInstance();
+ });
+}
- save() {
- os.apiWithDialog('admin/update-meta', {
- proxyAccountId: this.proxyAccountId,
- }).then(() => {
- fetchInstance();
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.proxyAccount,
+ icon: 'fas fa-ghost',
+ bg: 'var(--bg)',
}
});
</script>
diff --git a/packages/client/src/pages/admin/queue.chart.vue b/packages/client/src/pages/admin/queue.chart.vue
index 136fb63bb6..be63830bdd 100644
--- a/packages/client/src/pages/admin/queue.chart.vue
+++ b/packages/client/src/pages/admin/queue.chart.vue
@@ -26,62 +26,40 @@
</div>
</template>
-<script lang="ts">
-import { defineComponent, markRaw, onMounted, onUnmounted, ref } from 'vue';
+<script lang="ts" setup>
+import { onMounted, onUnmounted, ref } from 'vue';
import number from '@/filters/number';
import MkQueueChart from '@/components/queue-chart.vue';
import * as os from '@/os';
-export default defineComponent({
- components: {
- MkQueueChart
- },
+const activeSincePrevTick = ref(0);
+const active = ref(0);
+const waiting = ref(0);
+const delayed = ref(0);
+const jobs = ref([]);
- props: {
- domain: {
- type: String,
- required: true,
- },
- connection: {
- required: true,
- },
- },
+const props = defineProps<{
+ domain: string,
+ connection: any,
+}>();
- setup(props) {
- const activeSincePrevTick = ref(0);
- const active = ref(0);
- const waiting = ref(0);
- const delayed = ref(0);
- const jobs = ref([]);
+onMounted(() => {
+ os.api(props.domain === 'inbox' ? 'admin/queue/inbox-delayed' : props.domain === 'deliver' ? 'admin/queue/deliver-delayed' : null, {}).then(result => {
+ jobs.value = result;
+ });
- onMounted(() => {
- os.api(props.domain === 'inbox' ? 'admin/queue/inbox-delayed' : props.domain === 'deliver' ? 'admin/queue/deliver-delayed' : null, {}).then(result => {
- jobs.value = result;
- });
+ const onStats = (stats) => {
+ activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
+ active.value = stats[props.domain].active;
+ waiting.value = stats[props.domain].waiting;
+ delayed.value = stats[props.domain].delayed;
+ };
- const onStats = (stats) => {
- activeSincePrevTick.value = stats[props.domain].activeSincePrevTick;
- active.value = stats[props.domain].active;
- waiting.value = stats[props.domain].waiting;
- delayed.value = stats[props.domain].delayed;
- };
+ props.connection.on('stats', onStats);
- props.connection.on('stats', onStats);
-
- onUnmounted(() => {
- props.connection.off('stats', onStats);
- });
- });
-
- return {
- jobs,
- activeSincePrevTick,
- active,
- waiting,
- delayed,
- number,
- };
- },
+ onUnmounted(() => {
+ props.connection.off('stats', onStats);
+ });
});
</script>
diff --git a/packages/client/src/pages/admin/queue.vue b/packages/client/src/pages/admin/queue.vue
index 35fd618c82..656b18199f 100644
--- a/packages/client/src/pages/admin/queue.vue
+++ b/packages/client/src/pages/admin/queue.vue
@@ -6,71 +6,60 @@
<XQueue :connection="connection" domain="deliver">
<template #title>Out</template>
</XQueue>
- <MkButton danger @click="clear()"><i class="fas fa-trash-alt"></i> {{ $ts.clearQueue }}</MkButton>
+ <MkButton danger @click="clear()"><i class="fas fa-trash-alt"></i> {{ i18n.ts.clearQueue }}</MkButton>
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent, markRaw } from 'vue';
+<script lang="ts" setup>
+import { markRaw, onMounted, onBeforeUnmount, nextTick } from 'vue';
import MkButton from '@/components/ui/button.vue';
import XQueue from './queue.chart.vue';
import * as os from '@/os';
import { stream } from '@/stream';
import * as symbols from '@/symbols';
import * as config from '@/config';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkButton,
- XQueue,
- },
+const connection = markRaw(stream.useChannel('queueStats'));
- emits: ['info'],
+function clear() {
+ os.confirm({
+ type: 'warning',
+ title: i18n.ts.clearQueueConfirmTitle,
+ text: i18n.ts.clearQueueConfirmText,
+ }).then(({ canceled }) => {
+ if (canceled) return;
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.jobQueue,
- icon: 'fas fa-clipboard-list',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- icon: 'fas fa-up-right-from-square',
- text: this.$ts.dashboard,
- handler: () => {
- window.open(config.url + '/queue', '_blank');
- },
- }],
- },
- connection: markRaw(stream.useChannel('queueStats')),
- }
- },
+ os.apiWithDialog('admin/queue/clear');
+ });
+}
- mounted() {
- this.$nextTick(() => {
- this.connection.send('requestLog', {
- id: Math.random().toString().substr(2, 8),
- length: 200
- });
+onMounted(() => {
+ nextTick(() => {
+ connection.send('requestLog', {
+ id: Math.random().toString().substr(2, 8),
+ length: 200
});
- },
-
- beforeUnmount() {
- this.connection.dispose();
- },
+ });
+});
- methods: {
- clear() {
- os.confirm({
- type: 'warning',
- title: this.$ts.clearQueueConfirmTitle,
- text: this.$ts.clearQueueConfirmText,
- }).then(({ canceled }) => {
- if (canceled) return;
+onBeforeUnmount(() => {
+ connection.dispose();
+});
- os.apiWithDialog('admin/queue/clear', {});
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.jobQueue,
+ icon: 'fas fa-clipboard-list',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ icon: 'fas fa-up-right-from-square',
+ text: i18n.ts.dashboard,
+ handler: () => {
+ window.open(config.url + '/queue', '_blank');
+ },
+ }],
}
});
</script>
diff --git a/packages/client/src/pages/admin/relays.vue b/packages/client/src/pages/admin/relays.vue
index bb840db0a2..1a36bb4753 100644
--- a/packages/client/src/pages/admin/relays.vue
+++ b/packages/client/src/pages/admin/relays.vue
@@ -8,84 +8,71 @@
<i v-else class="fas fa-clock icon requesting"></i>
<span>{{ $t(`_relayStatus.${relay.status}`) }}</span>
</div>
- <MkButton class="button" inline danger @click="remove(relay.inbox)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
+ <MkButton class="button" inline danger @click="remove(relay.inbox)"><i class="fas fa-trash-alt"></i> {{ i18n.ts.remove }}</MkButton>
</div>
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import MkButton from '@/components/ui/button.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- MkButton,
- },
+let relays: any[] = $ref([]);
- emits: ['info'],
-
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.relays,
- icon: 'fas fa-globe',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- icon: 'fas fa-plus',
- text: this.$ts.addRelay,
- handler: this.addRelay,
- }],
- },
- relays: [],
- inbox: '',
- }
- },
+async function addRelay() {
+ const { canceled, result: inbox } = await os.inputText({
+ title: i18n.ts.addRelay,
+ type: 'url',
+ placeholder: i18n.ts.inboxUrl
+ });
+ if (canceled) return;
+ os.api('admin/relays/add', {
+ inbox
+ }).then((relay: any) => {
+ refresh();
+ }).catch((err: any) => {
+ os.alert({
+ type: 'error',
+ text: err.message || err
+ });
+ });
+}
- created() {
- this.refresh();
- },
+function remove(inbox: string) {
+ os.api('admin/relays/remove', {
+ inbox
+ }).then(() => {
+ refresh();
+ }).catch((err: any) => {
+ os.alert({
+ type: 'error',
+ text: err.message || err
+ });
+ });
+}
- methods: {
- async addRelay() {
- const { canceled, result: inbox } = await os.inputText({
- title: this.$ts.addRelay,
- type: 'url',
- placeholder: this.$ts.inboxUrl
- });
- if (canceled) return;
- os.api('admin/relays/add', {
- inbox
- }).then((relay: any) => {
- this.refresh();
- }).catch((e: any) => {
- os.alert({
- type: 'error',
- text: e.message || e
- });
- });
- },
+function refresh() {
+ os.api('admin/relays/list').then((relayList: any) => {
+ relays = relayList;
+ });
+}
- remove(inbox: string) {
- os.api('admin/relays/remove', {
- inbox
- }).then(() => {
- this.refresh();
- }).catch((e: any) => {
- os.alert({
- type: 'error',
- text: e.message || e
- });
- });
- },
+refresh();
- refresh() {
- os.api('admin/relays/list').then((relays: any) => {
- this.relays = relays;
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.relays,
+ icon: 'fas fa-globe',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ icon: 'fas fa-plus',
+ text: i18n.ts.addRelay,
+ handler: addRelay,
+ }],
}
});
</script>
diff --git a/packages/client/src/pages/admin/security.vue b/packages/client/src/pages/admin/security.vue
index d1c979b3e0..6b8f70cca5 100644
--- a/packages/client/src/pages/admin/security.vue
+++ b/packages/client/src/pages/admin/security.vue
@@ -4,10 +4,10 @@
<div class="_formRoot">
<FormFolder class="_formBlock">
<template #icon><i class="fas fa-shield-alt"></i></template>
- <template #label>{{ $ts.botProtection }}</template>
+ <template #label>{{ i18n.ts.botProtection }}</template>
<template v-if="enableHcaptcha" #suffix>hCaptcha</template>
<template v-else-if="enableRecaptcha" #suffix>reCAPTCHA</template>
- <template v-else #suffix>{{ $ts.none }} ({{ $ts.notRecommended }})</template>
+ <template v-else #suffix>{{ i18n.ts.none }} ({{ i18n.ts.notRecommended }})</template>
<XBotProtection/>
</FormFolder>
@@ -21,7 +21,7 @@
<template #label>Summaly Proxy URL</template>
</FormInput>
- <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+ <FormButton primary class="_formBlock" @click="save"><i class="fas fa-save"></i> {{ i18n.ts.save }}</FormButton>
</div>
</FormFolder>
</div>
@@ -29,8 +29,8 @@
</MkSpacer>
</template>
-<script lang="ts">
-import { defineAsyncComponent, defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormFolder from '@/components/form/folder.vue';
import FormSwitch from '@/components/form/switch.vue';
import FormInfo from '@/components/ui/info.vue';
@@ -42,49 +42,32 @@ import XBotProtection from './bot-protection.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- FormFolder,
- FormSwitch,
- FormInfo,
- FormSection,
- FormSuspense,
- FormButton,
- FormInput,
- XBotProtection,
- },
+let summalyProxy: string = $ref('');
+let enableHcaptcha: boolean = $ref(false);
+let enableRecaptcha: boolean = $ref(false);
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ summalyProxy = meta.summalyProxy;
+ enableHcaptcha = meta.enableHcaptcha;
+ enableRecaptcha = meta.enableRecaptcha;
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.security,
- icon: 'fas fa-lock',
- bg: 'var(--bg)',
- },
- summalyProxy: '',
- enableHcaptcha: false,
- enableRecaptcha: false,
- }
- },
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ summalyProxy,
+ }).then(() => {
+ fetchInstance();
+ });
+}
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.summalyProxy = meta.summalyProxy;
- this.enableHcaptcha = meta.enableHcaptcha;
- this.enableRecaptcha = meta.enableRecaptcha;
- },
-
- save() {
- os.apiWithDialog('admin/update-meta', {
- summalyProxy: this.summalyProxy,
- }).then(() => {
- fetchInstance();
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.security,
+ icon: 'fas fa-lock',
+ bg: 'var(--bg)',
}
});
</script>
diff --git a/packages/client/src/pages/admin/settings.vue b/packages/client/src/pages/admin/settings.vue
index f2970d0459..6dc30fe50b 100644
--- a/packages/client/src/pages/admin/settings.vue
+++ b/packages/client/src/pages/admin/settings.vue
@@ -3,104 +3,104 @@
<FormSuspense :p="init">
<div class="_formRoot">
<FormInput v-model="name" class="_formBlock">
- <template #label>{{ $ts.instanceName }}</template>
+ <template #label>{{ i18n.ts.instanceName }}</template>
</FormInput>
<FormTextarea v-model="description" class="_formBlock">
- <template #label>{{ $ts.instanceDescription }}</template>
+ <template #label>{{ i18n.ts.instanceDescription }}</template>
</FormTextarea>
<FormInput v-model="tosUrl" class="_formBlock">
<template #prefix><i class="fas fa-link"></i></template>
- <template #label>{{ $ts.tosUrl }}</template>
+ <template #label>{{ i18n.ts.tosUrl }}</template>
</FormInput>
<FormSplit :min-width="300">
<FormInput v-model="maintainerName" class="_formBlock">
- <template #label>{{ $ts.maintainerName }}</template>
+ <template #label>{{ i18n.ts.maintainerName }}</template>
</FormInput>
<FormInput v-model="maintainerEmail" type="email" class="_formBlock">
<template #prefix><i class="fas fa-envelope"></i></template>
- <template #label>{{ $ts.maintainerEmail }}</template>
+ <template #label>{{ i18n.ts.maintainerEmail }}</template>
</FormInput>
</FormSplit>
<FormTextarea v-model="pinnedUsers" class="_formBlock">
- <template #label>{{ $ts.pinnedUsers }}</template>
- <template #caption>{{ $ts.pinnedUsersDescription }}</template>
+ <template #label>{{ i18n.ts.pinnedUsers }}</template>
+ <template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
</FormTextarea>
<FormSection>
<FormSwitch v-model="enableRegistration" class="_formBlock">
- <template #label>{{ $ts.enableRegistration }}</template>
+ <template #label>{{ i18n.ts.enableRegistration }}</template>
</FormSwitch>
<FormSwitch v-model="emailRequiredForSignup" class="_formBlock">
- <template #label>{{ $ts.emailRequiredForSignup }}</template>
+ <template #label>{{ i18n.ts.emailRequiredForSignup }}</template>
</FormSwitch>
</FormSection>
<FormSection>
- <FormSwitch v-model="enableLocalTimeline" class="_formBlock">{{ $ts.enableLocalTimeline }}</FormSwitch>
- <FormSwitch v-model="enableGlobalTimeline" class="_formBlock">{{ $ts.enableGlobalTimeline }}</FormSwitch>
- <FormInfo class="_formBlock">{{ $ts.disablingTimelinesInfo }}</FormInfo>
+ <FormSwitch v-model="enableLocalTimeline" class="_formBlock">{{ i18n.ts.enableLocalTimeline }}</FormSwitch>
+ <FormSwitch v-model="enableGlobalTimeline" class="_formBlock">{{ i18n.ts.enableGlobalTimeline }}</FormSwitch>
+ <FormInfo class="_formBlock">{{ i18n.ts.disablingTimelinesInfo }}</FormInfo>
</FormSection>
<FormSection>
- <template #label>{{ $ts.theme }}</template>
+ <template #label>{{ i18n.ts.theme }}</template>
<FormInput v-model="iconUrl" class="_formBlock">
<template #prefix><i class="fas fa-link"></i></template>
- <template #label>{{ $ts.iconUrl }}</template>
+ <template #label>{{ i18n.ts.iconUrl }}</template>
</FormInput>
<FormInput v-model="bannerUrl" class="_formBlock">
<template #prefix><i class="fas fa-link"></i></template>
- <template #label>{{ $ts.bannerUrl }}</template>
+ <template #label>{{ i18n.ts.bannerUrl }}</template>
</FormInput>
<FormInput v-model="backgroundImageUrl" class="_formBlock">
<template #prefix><i class="fas fa-link"></i></template>
- <template #label>{{ $ts.backgroundImageUrl }}</template>
+ <template #label>{{ i18n.ts.backgroundImageUrl }}</template>
</FormInput>
<FormInput v-model="themeColor" class="_formBlock">
<template #prefix><i class="fas fa-palette"></i></template>
- <template #label>{{ $ts.themeColor }}</template>
+ <template #label>{{ i18n.ts.themeColor }}</template>
<template #caption>#RRGGBB</template>
</FormInput>
<FormTextarea v-model="defaultLightTheme" class="_formBlock">
- <template #label>{{ $ts.instanceDefaultLightTheme }}</template>
- <template #caption>{{ $ts.instanceDefaultThemeDescription }}</template>
+ <template #label>{{ i18n.ts.instanceDefaultLightTheme }}</template>
+ <template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
</FormTextarea>
<FormTextarea v-model="defaultDarkTheme" class="_formBlock">
- <template #label>{{ $ts.instanceDefaultDarkTheme }}</template>
- <template #caption>{{ $ts.instanceDefaultThemeDescription }}</template>
+ <template #label>{{ i18n.ts.instanceDefaultDarkTheme }}</template>
+ <template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
</FormTextarea>
</FormSection>
<FormSection>
- <template #label>{{ $ts.files }}</template>
+ <template #label>{{ i18n.ts.files }}</template>
<FormSwitch v-model="cacheRemoteFiles" class="_formBlock">
- <template #label>{{ $ts.cacheRemoteFiles }}</template>
- <template #caption>{{ $ts.cacheRemoteFilesDescription }}</template>
+ <template #label>{{ i18n.ts.cacheRemoteFiles }}</template>
+ <template #caption>{{ i18n.ts.cacheRemoteFilesDescription }}</template>
</FormSwitch>
<FormSplit :min-width="280">
<FormInput v-model="localDriveCapacityMb" type="number" class="_formBlock">
- <template #label>{{ $ts.driveCapacityPerLocalAccount }}</template>
+ <template #label>{{ i18n.ts.driveCapacityPerLocalAccount }}</template>
<template #suffix>MB</template>
- <template #caption>{{ $ts.inMb }}</template>
+ <template #caption>{{ i18n.ts.inMb }}</template>
</FormInput>
<FormInput v-model="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles" class="_formBlock">
- <template #label>{{ $ts.driveCapacityPerRemoteAccount }}</template>
+ <template #label>{{ i18n.ts.driveCapacityPerRemoteAccount }}</template>
<template #suffix>MB</template>
- <template #caption>{{ $ts.inMb }}</template>
+ <template #caption>{{ i18n.ts.inMb }}</template>
</FormInput>
</FormSplit>
</FormSection>
@@ -109,8 +109,8 @@
<template #label>ServiceWorker</template>
<FormSwitch v-model="enableServiceWorker" class="_formBlock">
- <template #label>{{ $ts.enableServiceworker }}</template>
- <template #caption>{{ $ts.serviceworkerInfo }}</template>
+ <template #label>{{ i18n.ts.enableServiceworker }}</template>
+ <template #caption>{{ i18n.ts.serviceworkerInfo }}</template>
</FormSwitch>
<template v-if="enableServiceWorker">
@@ -142,8 +142,8 @@
</MkSpacer>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { } from 'vue';
import FormSwitch from '@/components/form/switch.vue';
import FormInput from '@/components/form/input.vue';
import FormTextarea from '@/components/form/textarea.vue';
@@ -154,119 +154,103 @@ import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
import { fetchInstance } from '@/instance';
+import { i18n } from '@/i18n';
-export default defineComponent({
- components: {
- FormSwitch,
- FormInput,
- FormSuspense,
- FormTextarea,
- FormInfo,
- FormSection,
- FormSplit,
- },
+let name: string | null = $ref(null);
+let description: string | null = $ref(null);
+let tosUrl: string | null = $ref(null);
+let maintainerName: string | null = $ref(null);
+let maintainerEmail: string | null = $ref(null);
+let iconUrl: string | null = $ref(null);
+let bannerUrl: string | null = $ref(null);
+let backgroundImageUrl: string | null = $ref(null);
+let themeColor: any = $ref(null);
+let defaultLightTheme: any = $ref(null);
+let defaultDarkTheme: any = $ref(null);
+let enableLocalTimeline: boolean = $ref(false);
+let enableGlobalTimeline: boolean = $ref(false);
+let pinnedUsers: string = $ref('');
+let cacheRemoteFiles: boolean = $ref(false);
+let localDriveCapacityMb: any = $ref(0);
+let remoteDriveCapacityMb: any = $ref(0);
+let enableRegistration: boolean = $ref(false);
+let emailRequiredForSignup: boolean = $ref(false);
+let enableServiceWorker: boolean = $ref(false);
+let swPublicKey: any = $ref(null);
+let swPrivateKey: any = $ref(null);
+let deeplAuthKey: string = $ref('');
+let deeplIsPro: boolean = $ref(false);
- emits: ['info'],
+async function init() {
+ const meta = await os.api('admin/meta');
+ name = meta.name;
+ description = meta.description;
+ tosUrl = meta.tosUrl;
+ iconUrl = meta.iconUrl;
+ bannerUrl = meta.bannerUrl;
+ backgroundImageUrl = meta.backgroundImageUrl;
+ themeColor = meta.themeColor;
+ defaultLightTheme = meta.defaultLightTheme;
+ defaultDarkTheme = meta.defaultDarkTheme;
+ maintainerName = meta.maintainerName;
+ maintainerEmail = meta.maintainerEmail;
+ enableLocalTimeline = !meta.disableLocalTimeline;
+ enableGlobalTimeline = !meta.disableGlobalTimeline;
+ pinnedUsers = meta.pinnedUsers.join('\n');
+ cacheRemoteFiles = meta.cacheRemoteFiles;
+ localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
+ remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
+ enableRegistration = !meta.disableRegistration;
+ emailRequiredForSignup = meta.emailRequiredForSignup;
+ enableServiceWorker = meta.enableServiceWorker;
+ swPublicKey = meta.swPublickey;
+ swPrivateKey = meta.swPrivateKey;
+ deeplAuthKey = meta.deeplAuthKey;
+ deeplIsPro = meta.deeplIsPro;
+}
- data() {
- return {
- [symbols.PAGE_INFO]: {
- title: this.$ts.general,
- icon: 'fas fa-cog',
- bg: 'var(--bg)',
- actions: [{
- asFullButton: true,
- icon: 'fas fa-check',
- text: this.$ts.save,
- handler: this.save,
- }],
- },
- name: null,
- description: null,
- tosUrl: null as string | null,
- maintainerName: null,
- maintainerEmail: null,
- iconUrl: null,
- bannerUrl: null,
- backgroundImageUrl: null,
- themeColor: null,
- defaultLightTheme: null,
- defaultDarkTheme: null,
- enableLocalTimeline: false,
- enableGlobalTimeline: false,
- pinnedUsers: '',
- cacheRemoteFiles: false,
- localDriveCapacityMb: 0,
- remoteDriveCapacityMb: 0,
- enableRegistration: false,
- emailRequiredForSignup: false,
- enableServiceWorker: false,
- swPublicKey: null,
- swPrivateKey: null,
- deeplAuthKey: '',
- deeplIsPro: false,
- }
- },
+function save() {
+ os.apiWithDialog('admin/update-meta', {
+ name,
+ description,
+ tosUrl,
+ iconUrl,
+ bannerUrl,
+ backgroundImageUrl,
+ themeColor: themeColor === '' ? null : themeColor,
+ defaultLightTheme: defaultLightTheme === '' ? null : defaultLightTheme,
+ defaultDarkTheme: defaultDarkTheme === '' ? null : defaultDarkTheme,
+ maintainerName,
+ maintainerEmail,
+ disableLocalTimeline: !enableLocalTimeline,
+ disableGlobalTimeline: !enableGlobalTimeline,
+ pinnedUsers: pinnedUsers.split('\n'),
+ cacheRemoteFiles,
+ localDriveCapacityMb: parseInt(localDriveCapacityMb, 10),
+ remoteDriveCapacityMb: parseInt(remoteDriveCapacityMb, 10),
+ disableRegistration: !enableRegistration,
+ emailRequiredForSignup,
+ enableServiceWorker,
+ swPublicKey,
+ swPrivateKey,
+ deeplAuthKey,
+ deeplIsPro,
+ }).then(() => {
+ fetchInstance();
+ });
+}
- methods: {
- async init() {
- const meta = await os.api('admin/meta');
- this.name = meta.name;
- this.description = meta.description;
- this.tosUrl = meta.tosUrl;
- this.iconUrl = meta.iconUrl;
- this.bannerUrl = meta.bannerUrl;
- this.backgroundImageUrl = meta.backgroundImageUrl;
- this.themeColor = meta.themeColor;
- this.defaultLightTheme = meta.defaultLightTheme;
- this.defaultDarkTheme = meta.defaultDarkTheme;
- this.maintainerName = meta.maintainerName;
- this.maintainerEmail = meta.maintainerEmail;
- this.enableLocalTimeline = !meta.disableLocalTimeline;
- this.enableGlobalTimeline = !meta.disableGlobalTimeline;
- this.pinnedUsers = meta.pinnedUsers.join('\n');
- this.cacheRemoteFiles = meta.cacheRemoteFiles;
- this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
- this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
- this.enableRegistration = !meta.disableRegistration;
- this.emailRequiredForSignup = meta.emailRequiredForSignup;
- this.enableServiceWorker = meta.enableServiceWorker;
- this.swPublicKey = meta.swPublickey;
- this.swPrivateKey = meta.swPrivateKey;
- this.deeplAuthKey = meta.deeplAuthKey;
- this.deeplIsPro = meta.deeplIsPro;
- },
-
- save() {
- os.apiWithDialog('admin/update-meta', {
- name: this.name,
- description: this.description,
- tosUrl: this.tosUrl,
- iconUrl: this.iconUrl,
- bannerUrl: this.bannerUrl,
- backgroundImageUrl: this.backgroundImageUrl,
- themeColor: this.themeColor === '' ? null : this.themeColor,
- defaultLightTheme: this.defaultLightTheme === '' ? null : this.defaultLightTheme,
- defaultDarkTheme: this.defaultDarkTheme === '' ? null : this.defaultDarkTheme,
- maintainerName: this.maintainerName,
- maintainerEmail: this.maintainerEmail,
- disableLocalTimeline: !this.enableLocalTimeline,
- disableGlobalTimeline: !this.enableGlobalTimeline,
- pinnedUsers: this.pinnedUsers.split('\n'),
- cacheRemoteFiles: this.cacheRemoteFiles,
- localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
- remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
- disableRegistration: !this.enableRegistration,
- emailRequiredForSignup: this.emailRequiredForSignup,
- enableServiceWorker: this.enableServiceWorker,
- swPublicKey: this.swPublicKey,
- swPrivateKey: this.swPrivateKey,
- deeplAuthKey: this.deeplAuthKey,
- deeplIsPro: this.deeplIsPro,
- }).then(() => {
- fetchInstance();
- });
- }
+defineExpose({
+ [symbols.PAGE_INFO]: {
+ title: i18n.ts.general,
+ icon: 'fas fa-cog',
+ bg: 'var(--bg)',
+ actions: [{
+ asFullButton: true,
+ icon: 'fas fa-check',
+ text: i18n.ts.save,
+ handler: save,
+ }],
}
});
</script>