Compare commits

...

17 Commits

Author SHA1 Message Date
github-actions[bot]
76b9bc478a Bump version to 2024.9.0-alpha.5 2024-09-22 11:49:02 +00:00
syuilo
f93a575c3a 🎨 2024-09-22 20:44:24 +09:00
syuilo
e6e4182b53 enhance(frontend): tweak control panel 2024-09-22 20:23:20 +09:00
syuilo
736d8283c1 refactor 2024-09-22 20:21:06 +09:00
syuilo
0041ad3e69 enhance(frontend): tweak control panel 2024-09-22 20:14:19 +09:00
syuilo
973d8366c3 🎨 2024-09-22 20:14:09 +09:00
syuilo
2762e29f7f 🎨 2024-09-22 20:02:47 +09:00
かっこかり
0bbeb40c0a fix typo (#14609) 2024-09-22 19:30:36 +09:00
かっこかり
e87cbd2a36 fix(frontend): lint fixe for tweak control panel (#14610) 2024-09-22 19:13:30 +09:00
github-actions[bot]
1d5a3023f4 Bump version to 2024.9.0-alpha.4 2024-09-22 09:44:00 +00:00
syuilo
bd5f25c678 fix rbt bug? 2024-09-22 18:40:05 +09:00
syuilo
6ba97a7763 enhance(frontend): tweak control panel 2024-09-22 18:35:10 +09:00
syuilo
d435d04eaf enhance(frontend): tweak control panel 2024-09-22 18:26:21 +09:00
かっこかり
01ec708020 ffix(frontend): lint fixes for tweak control panel (#14607) 2024-09-22 17:50:54 +09:00
syuilo
0e92cbf905 enhance(frontend): tweak control panel 2024-09-22 16:24:53 +09:00
syuilo
8ad9f7209b enhance(frontend): tweak control panel 2024-09-22 16:16:50 +09:00
syuilo
3df1bb2d71 enhance(frontend): tweak control panel 2024-09-22 16:01:13 +09:00
18 changed files with 459 additions and 359 deletions

4
locales/index.d.ts vendored
View File

@@ -5092,6 +5092,10 @@ export interface Locale extends ILocale {
* これ以上このクリップにノートを追加できません。
*/
"clipNoteLimitExceeded": string;
/**
* パフォーマンス
*/
"performance": string;
"_delivery": {
/**
* 配信状態

View File

@@ -1269,6 +1269,7 @@ fromX: "{x}から"
genEmbedCode: "埋め込みコードを生成"
noteOfThisUser: "このユーザーのノート一覧"
clipNoteLimitExceeded: "これ以上このクリップにノートを追加できません。"
performance: "パフォーマンス"
_delivery:
status: "配信状態"

View File

@@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "2024.9.0-alpha.3",
"version": "2024.9.0-alpha.5",
"codename": "nasubi",
"repository": {
"type": "git",

View File

@@ -337,6 +337,7 @@ export class ReactionService {
//#endregion
}
// TODO: 廃止
/**
* 文字列タイプのレガシーな形式のリアクションを現在の形式に変換しつつ、
* データベース上には存在する「0個のリアクションがついている」という情報を削除する。

View File

@@ -307,7 +307,7 @@ export class NoteEntityService implements OnModuleInit {
skipHide?: boolean;
withReactionAndUserPairCache?: boolean;
_hint_?: {
bufferdReactions: Map<MiNote['id'], { deltas: Record<string, number>; pairs: ([MiUser['id'], string])[] }> | null;
bufferedReactions: Map<MiNote['id'], { deltas: Record<string, number>; pairs: ([MiUser['id'], string])[] }> | null;
myReactions: Map<MiNote['id'], string | null>;
packedFiles: Map<MiNote['fileIds'][number], Packed<'DriveFile'> | null>;
packedUsers: Map<MiUser['id'], Packed<'UserLite'>>
@@ -324,19 +324,19 @@ export class NoteEntityService implements OnModuleInit {
const note = typeof src === 'object' ? src : await this.noteLoader.load(src);
const host = note.userHost;
const bufferdReactions = opts._hint_?.bufferdReactions != null
? (opts._hint_.bufferdReactions.get(note.id) ?? { deltas: {}, pairs: [] })
const bufferedReactions = opts._hint_?.bufferedReactions != null
? (opts._hint_.bufferedReactions.get(note.id) ?? { deltas: {}, pairs: [] })
: this.meta.enableReactionsBuffering
? await this.reactionsBufferingService.get(note.id)
: { deltas: {}, pairs: [] };
const reactions = mergeReactions(note.reactions, bufferdReactions.deltas ?? {});
const reactions = mergeReactions(this.reactionService.convertLegacyReactions(note.reactions), bufferedReactions.deltas ?? {});
for (const [name, count] of Object.entries(reactions)) {
if (count <= 0) {
delete reactions[name];
}
}
const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferdReactions.pairs.map(x => x.join('/')));
const reactionAndUserPairCache = note.reactionAndUserPairCache.concat(bufferedReactions.pairs.map(x => x.join('/')));
let text = note.text;
@@ -439,7 +439,7 @@ export class NoteEntityService implements OnModuleInit {
) {
if (notes.length === 0) return [];
const bufferdReactions = this.meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(notes.map(x => x.id)) : null;
const bufferedReactions = this.meta.enableReactionsBuffering ? await this.reactionsBufferingService.getMany(notes.map(x => x.id)) : null;
const meId = me ? me.id : null;
const myReactionsMap = new Map<MiNote['id'], string | null>();
@@ -451,11 +451,11 @@ export class NoteEntityService implements OnModuleInit {
for (const note of notes) {
if (note.renote && (note.text == null && note.fileIds.length === 0)) { // pure renote
const reactionsCount = Object.values(mergeReactions(note.renote.reactions, bufferdReactions?.get(note.renote.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
const reactionsCount = Object.values(mergeReactions(note.renote.reactions, bufferedReactions?.get(note.renote.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
if (reactionsCount === 0) {
myReactionsMap.set(note.renote.id, null);
} else if (reactionsCount <= note.renote.reactionAndUserPairCache.length + (bufferdReactions?.get(note.renote.id)?.pairs.length ?? 0)) {
const pairInBuffer = bufferdReactions?.get(note.renote.id)?.pairs.find(p => p[0] === meId);
} else if (reactionsCount <= note.renote.reactionAndUserPairCache.length + (bufferedReactions?.get(note.renote.id)?.pairs.length ?? 0)) {
const pairInBuffer = bufferedReactions?.get(note.renote.id)?.pairs.find(p => p[0] === meId);
if (pairInBuffer) {
myReactionsMap.set(note.renote.id, pairInBuffer[1]);
} else {
@@ -467,11 +467,11 @@ export class NoteEntityService implements OnModuleInit {
}
} else {
if (note.id < oldId) {
const reactionsCount = Object.values(mergeReactions(note.reactions, bufferdReactions?.get(note.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
const reactionsCount = Object.values(mergeReactions(note.reactions, bufferedReactions?.get(note.id)?.deltas ?? {})).reduce((a, b) => a + b, 0);
if (reactionsCount === 0) {
myReactionsMap.set(note.id, null);
} else if (reactionsCount <= note.reactionAndUserPairCache.length + (bufferdReactions?.get(note.id)?.pairs.length ?? 0)) {
const pairInBuffer = bufferdReactions?.get(note.id)?.pairs.find(p => p[0] === meId);
} else if (reactionsCount <= note.reactionAndUserPairCache.length + (bufferedReactions?.get(note.id)?.pairs.length ?? 0)) {
const pairInBuffer = bufferedReactions?.get(note.id)?.pairs.find(p => p[0] === meId);
if (pairInBuffer) {
myReactionsMap.set(note.id, pairInBuffer[1]);
} else {
@@ -512,7 +512,7 @@ export class NoteEntityService implements OnModuleInit {
return await Promise.all(notes.map(n => this.pack(n, me, {
...options,
_hint_: {
bufferdReactions,
bufferedReactions,
myReactions: myReactionsMap,
packedFiles,
packedUsers,

View File

@@ -246,7 +246,7 @@ function onMousedown(evt: MouseEvent): void {
}
&:disabled {
opacity: 0.7;
opacity: 0.5;
}
&:focus-visible {

View File

@@ -41,6 +41,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSpacer :marginMin="14" :marginMax="22">
<slot></slot>
</MkSpacer>
<div v-if="$slots.footer" :class="$style.footer">
<slot name="footer"></slot>
</div>
</div>
</KeepAlive>
</Transition>
@@ -224,4 +227,16 @@ onMounted(() => {
background: var(--bg);
}
}
.footer {
position: sticky !important;
z-index: 1;
bottom: var(--stickyBottom, 0px);
left: 0;
padding: 9px 12px;
background: var(--acrylicBg);
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
border-radius: 0 0 6px 6px;
}
</style>

View File

@@ -12,6 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="bodyEl"
:data-sticky-container-header-height="headerHeight"
:data-sticky-container-footer-height="footerHeight"
style="position: relative; z-index: 0;"
>
<slot></slot>
</div>
@@ -83,14 +84,14 @@ onMounted(() => {
if (headerEl.value != null) {
headerEl.value.style.position = 'sticky';
headerEl.value.style.top = 'var(--stickyTop, 0)';
headerEl.value.style.zIndex = '1000';
headerEl.value.style.zIndex = '1';
observer.observe(headerEl.value);
}
if (footerEl.value != null) {
footerEl.value.style.position = 'sticky';
footerEl.value.style.bottom = 'var(--stickyBottom, 0)';
footerEl.value.style.zIndex = '1000';
footerEl.value.style.zIndex = '1';
observer.observe(footerEl.value);
}
});

View File

@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
<FormSuspense :p="init">
<FormSection>
<MkFolder>
<template #label>DeepL Translation</template>
<div class="_gaps_m">
@@ -19,17 +19,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="deeplIsPro">
<template #label>Pro account</template>
</MkSwitch>
<MkButton primary @click="save_deepl">Save</MkButton>
</div>
</FormSection>
</MkFolder>
</FormSuspense>
</MkSpacer>
<template #footer>
<div :class="$style.footer">
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
<MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
</MkSpacer>
</div>
</template>
</MkStickyContainer>
</template>
@@ -40,12 +34,12 @@ import MkInput from '@/components/MkInput.vue';
import MkButton from '@/components/MkButton.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import FormSuspense from '@/components/form/suspense.vue';
import FormSection from '@/components/form/section.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkFolder from '@/components/MkFolder.vue';
const deeplAuthKey = ref<string>('');
const deeplIsPro = ref<boolean>(false);
@@ -56,7 +50,7 @@ async function init() {
deeplIsPro.value = meta.deeplIsPro;
}
function save() {
function save_deepl() {
os.apiWithDialog('admin/update-meta', {
deeplAuthKey: deeplAuthKey.value,
deeplIsPro: deeplIsPro.value,
@@ -74,10 +68,3 @@ definePageMetadata(() => ({
icon: 'ti ti-link',
}));
</script>
<style lang="scss" module>
.footer {
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
}
</style>

View File

@@ -199,16 +199,6 @@ const menuDef = computed(() => [{
text: i18n.ts.relays,
to: '/admin/relays',
active: currentPage.value?.route.name === 'relays',
}, {
icon: 'ti ti-ban',
text: i18n.ts.instanceBlocking,
to: '/admin/instance-block',
active: currentPage.value?.route.name === 'instance-block',
}, {
icon: 'ti ti-ghost',
text: i18n.ts.proxyAccount,
to: '/admin/proxy-account',
active: currentPage.value?.route.name === 'proxy-account',
}, {
icon: 'ti ti-link',
text: i18n.ts.externalServices,
@@ -220,10 +210,10 @@ const menuDef = computed(() => [{
to: '/admin/system-webhook',
active: currentPage.value?.route.name === 'system-webhook',
}, {
icon: 'ti ti-adjustments',
text: i18n.ts.other,
to: '/admin/other-settings',
active: currentPage.value?.route.name === 'other-settings',
icon: 'ti ti-bolt',
text: i18n.ts.performance,
to: '/admin/performance',
active: currentPage.value?.route.name === 'performance',
}],
}, {
title: i18n.ts.info,

View File

@@ -1,84 +0,0 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer>
<template #header><XHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
<FormSuspense :p="init">
<template v-if="tab === 'block'">
<MkTextarea v-model="blockedHosts">
<span>{{ i18n.ts.blockedInstances }}</span>
<template #caption>{{ i18n.ts.blockedInstancesDescription }}</template>
</MkTextarea>
</template>
<template v-else-if="tab === 'silence'">
<MkTextarea v-model="silencedHosts" class="_formBlock">
<span>{{ i18n.ts.silencedInstances }}</span>
<template #caption>{{ i18n.ts.silencedInstancesDescription }}</template>
</MkTextarea>
<MkTextarea v-model="mediaSilencedHosts" class="_formBlock">
<span>{{ i18n.ts.mediaSilencedInstances }}</span>
<template #caption>{{ i18n.ts.mediaSilencedInstancesDescription }}</template>
</MkTextarea>
</template>
<MkButton primary @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
</FormSuspense>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import XHeader from './_header_.vue';
import MkButton from '@/components/MkButton.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const blockedHosts = ref<string>('');
const silencedHosts = ref<string>('');
const mediaSilencedHosts = ref<string>('');
const tab = ref('block');
async function init() {
const meta = await misskeyApi('admin/meta');
blockedHosts.value = meta.blockedHosts.join('\n');
silencedHosts.value = meta.silencedHosts.join('\n');
mediaSilencedHosts.value = meta.mediaSilencedHosts.join('\n');
}
function save() {
os.apiWithDialog('admin/update-meta', {
blockedHosts: blockedHosts.value.split('\n') || [],
silencedHosts: silencedHosts.value.split('\n') || [],
mediaSilencedHosts: mediaSilencedHosts.value.split('\n') || [],
}).then(() => {
fetchInstance(true);
});
}
const headerActions = computed(() => []);
const headerTabs = computed(() => [{
key: 'block',
title: i18n.ts.block,
icon: 'ti ti-ban',
}, {
key: 'silence',
title: i18n.ts.silence,
icon: 'ti ti-eye-off',
}]);
definePageMetadata(() => ({
title: i18n.ts.instanceBlocking,
icon: 'ti ti-ban',
}));
</script>

View File

@@ -10,61 +10,102 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
<FormSuspense :p="init">
<div class="_gaps_m">
<MkSwitch v-model="enableRegistration">
<MkSwitch v-model="enableRegistration" @change="onChange_enableRegistration">
<template #label>{{ i18n.ts.enableRegistration }}</template>
</MkSwitch>
<MkSwitch v-model="emailRequiredForSignup">
<MkSwitch v-model="emailRequiredForSignup" @change="onChange_emailRequiredForSignup">
<template #label>{{ i18n.ts.emailRequiredForSignup }}</template>
</MkSwitch>
<FormLink to="/admin/server-rules">{{ i18n.ts.serverRules }}</FormLink>
<MkInput v-model="tosUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.tosUrl }}</template>
</MkInput>
<MkInput v-model="privacyPolicyUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.privacyPolicyUrl }}</template>
</MkInput>
<MkInput v-model="inquiryUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts._serverSettings.inquiryUrl }}</template>
<template #caption>{{ i18n.ts._serverSettings.inquiryUrlDescription }}</template>
</MkInput>
<MkTextarea v-model="preservedUsernames">
<MkFolder>
<template #icon><i class="ti ti-lock-star"></i></template>
<template #label>{{ i18n.ts.preservedUsernames }}</template>
<template #caption>{{ i18n.ts.preservedUsernamesDescription }}</template>
</MkTextarea>
<MkTextarea v-model="sensitiveWords">
<div class="_gaps">
<MkTextarea v-model="preservedUsernames">
<template #caption>{{ i18n.ts.preservedUsernamesDescription }}</template>
</MkTextarea>
<MkButton primary @click="save_preservedUsernames">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-message-exclamation"></i></template>
<template #label>{{ i18n.ts.sensitiveWords }}</template>
<template #caption>{{ i18n.ts.sensitiveWordsDescription }}<br>{{ i18n.ts.sensitiveWordsDescription2 }}</template>
</MkTextarea>
<MkTextarea v-model="prohibitedWords">
<div class="_gaps">
<MkTextarea v-model="sensitiveWords">
<template #caption>{{ i18n.ts.sensitiveWordsDescription }}<br>{{ i18n.ts.sensitiveWordsDescription2 }}</template>
</MkTextarea>
<MkButton primary @click="save_sensitiveWords">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-message-x"></i></template>
<template #label>{{ i18n.ts.prohibitedWords }}</template>
<template #caption>{{ i18n.ts.prohibitedWordsDescription }}<br>{{ i18n.ts.prohibitedWordsDescription2 }}</template>
</MkTextarea>
<MkTextarea v-model="hiddenTags">
<div class="_gaps">
<MkTextarea v-model="prohibitedWords">
<template #caption>{{ i18n.ts.prohibitedWordsDescription }}<br>{{ i18n.ts.prohibitedWordsDescription2 }}</template>
</MkTextarea>
<MkButton primary @click="save_prohibitedWords">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-eye-off"></i></template>
<template #label>{{ i18n.ts.hiddenTags }}</template>
<template #caption>{{ i18n.ts.hiddenTagsDescription }}</template>
</MkTextarea>
<div class="_gaps">
<MkTextarea v-model="hiddenTags">
<template #caption>{{ i18n.ts.hiddenTagsDescription }}</template>
</MkTextarea>
<MkButton primary @click="save_hiddenTags">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-eye-off"></i></template>
<template #label>{{ i18n.ts.silencedInstances }}</template>
<div class="_gaps">
<MkTextarea v-model="silencedHosts">
<template #caption>{{ i18n.ts.silencedInstancesDescription }}</template>
</MkTextarea>
<MkButton primary @click="save_silencedHosts">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-eye-off"></i></template>
<template #label>{{ i18n.ts.mediaSilencedInstances }}</template>
<div class="_gaps">
<MkTextarea v-model="mediaSilencedHosts">
<template #caption>{{ i18n.ts.mediaSilencedInstancesDescription }}</template>
</MkTextarea>
<MkButton primary @click="save_mediaSilencedHosts">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-ban"></i></template>
<template #label>{{ i18n.ts.blockedInstances }}</template>
<div class="_gaps">
<MkTextarea v-model="blockedHosts">
<template #caption>{{ i18n.ts.blockedInstancesDescription }}</template>
</MkTextarea>
<MkButton primary @click="save_blockedHosts">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
</div>
</FormSuspense>
</MkSpacer>
<template #footer>
<div :class="$style.footer">
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
<MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
</MkSpacer>
</div>
</template>
</MkStickyContainer>
</div>
</template>
@@ -83,6 +124,7 @@ import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
import FormLink from '@/components/form/link.vue';
import MkFolder from '@/components/MkFolder.vue';
const enableRegistration = ref<boolean>(false);
const emailRequiredForSignup = ref<boolean>(false);
@@ -90,9 +132,9 @@ const sensitiveWords = ref<string>('');
const prohibitedWords = ref<string>('');
const hiddenTags = ref<string>('');
const preservedUsernames = ref<string>('');
const tosUrl = ref<string | null>(null);
const privacyPolicyUrl = ref<string | null>(null);
const inquiryUrl = ref<string | null>(null);
const blockedHosts = ref<string>('');
const silencedHosts = ref<string>('');
const mediaSilencedHosts = ref<string>('');
async function init() {
const meta = await misskeyApi('admin/meta');
@@ -102,27 +144,83 @@ async function init() {
prohibitedWords.value = meta.prohibitedWords.join('\n');
hiddenTags.value = meta.hiddenTags.join('\n');
preservedUsernames.value = meta.preservedUsernames.join('\n');
tosUrl.value = meta.tosUrl;
privacyPolicyUrl.value = meta.privacyPolicyUrl;
inquiryUrl.value = meta.inquiryUrl;
blockedHosts.value = meta.blockedHosts.join('\n');
silencedHosts.value = meta.silencedHosts.join('\n');
mediaSilencedHosts.value = meta.mediaSilencedHosts.join('\n');
}
function save() {
function onChange_enableRegistration(value: boolean) {
os.apiWithDialog('admin/update-meta', {
disableRegistration: !value,
}).then(() => {
fetchInstance(true);
});
}
function onChange_emailRequiredForSignup(value: boolean) {
os.apiWithDialog('admin/update-meta', {
emailRequiredForSignup: value,
}).then(() => {
fetchInstance(true);
});
}
function save_preservedUsernames() {
os.apiWithDialog('admin/update-meta', {
disableRegistration: !enableRegistration.value,
emailRequiredForSignup: emailRequiredForSignup.value,
tosUrl: tosUrl.value,
privacyPolicyUrl: privacyPolicyUrl.value,
inquiryUrl: inquiryUrl.value,
sensitiveWords: sensitiveWords.value.split('\n'),
prohibitedWords: prohibitedWords.value.split('\n'),
hiddenTags: hiddenTags.value.split('\n'),
preservedUsernames: preservedUsernames.value.split('\n'),
}).then(() => {
fetchInstance(true);
});
}
function save_sensitiveWords() {
os.apiWithDialog('admin/update-meta', {
sensitiveWords: sensitiveWords.value.split('\n'),
}).then(() => {
fetchInstance(true);
});
}
function save_prohibitedWords() {
os.apiWithDialog('admin/update-meta', {
prohibitedWords: prohibitedWords.value.split('\n'),
}).then(() => {
fetchInstance(true);
});
}
function save_hiddenTags() {
os.apiWithDialog('admin/update-meta', {
hiddenTags: hiddenTags.value.split('\n'),
}).then(() => {
fetchInstance(true);
});
}
function save_blockedHosts() {
os.apiWithDialog('admin/update-meta', {
blockedHosts: blockedHosts.value.split('\n') || [],
}).then(() => {
fetchInstance(true);
});
}
function save_silencedHosts() {
os.apiWithDialog('admin/update-meta', {
silencedHosts: silencedHosts.value.split('\n') || [],
}).then(() => {
fetchInstance(true);
});
}
function save_mediaSilencedHosts() {
os.apiWithDialog('admin/update-meta', {
mediaSilencedHosts: mediaSilencedHosts.value.split('\n') || [],
}).then(() => {
fetchInstance(true);
});
}
const headerTabs = computed(() => []);
definePageMetadata(() => ({
@@ -130,10 +228,3 @@ definePageMetadata(() => ({
icon: 'ti ti-shield',
}));
</script>
<style lang="scss" module>
.footer {
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
}
</style>

View File

@@ -10,28 +10,28 @@ SPDX-License-Identifier: AGPL-3.0-only
<FormSuspense :p="init">
<div class="_gaps">
<div class="_panel" style="padding: 16px;">
<MkSwitch v-model="enableServerMachineStats">
<MkSwitch v-model="enableServerMachineStats" @change="onChange_enableServerMachineStats">
<template #label>{{ i18n.ts.enableServerMachineStats }}</template>
<template #caption>{{ i18n.ts.turnOffToImprovePerformance }}</template>
</MkSwitch>
</div>
<div class="_panel" style="padding: 16px;">
<MkSwitch v-model="enableIdenticonGeneration">
<MkSwitch v-model="enableIdenticonGeneration" @change="onChange_enableIdenticonGeneration">
<template #label>{{ i18n.ts.enableIdenticonGeneration }}</template>
<template #caption>{{ i18n.ts.turnOffToImprovePerformance }}</template>
</MkSwitch>
</div>
<div class="_panel" style="padding: 16px;">
<MkSwitch v-model="enableChartsForRemoteUser">
<MkSwitch v-model="enableChartsForRemoteUser" @change="onChange_enableChartsForRemoteUser">
<template #label>{{ i18n.ts.enableChartsForRemoteUser }}</template>
<template #caption>{{ i18n.ts.turnOffToImprovePerformance }}</template>
</MkSwitch>
</div>
<div class="_panel" style="padding: 16px;">
<MkSwitch v-model="enableChartsForFederatedInstances">
<MkSwitch v-model="enableChartsForFederatedInstances" @change="onChange_enableChartsForFederatedInstances">
<template #label>{{ i18n.ts.enableChartsForFederatedInstances }}</template>
<template #caption>{{ i18n.ts.turnOffToImprovePerformance }}</template>
</MkSwitch>
@@ -42,6 +42,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>Misskey® Fan-out Timeline Technology (FTT)</template>
<template v-if="enableFanoutTimeline" #suffix>Enabled</template>
<template v-else #suffix>Disabled</template>
<template v-if="isFttModified" #footer>
<MkButton primary rounded @click="saveFtt">{{ i18n.ts.save }}</MkButton>
</template>
<div class="_gaps_m">
<MkSwitch v-model="enableFanoutTimeline">
@@ -77,9 +80,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkFolder :defaultOpen="true">
<template #icon><i class="ti ti-bolt"></i></template>
<template #label>Misskey® Reactions Buffering Technology (RBT)<span class="_beta">{{ i18n.ts.beta }}</span></template>
<template #label>Misskey® Reactions Boost Technology (RBT)<span class="_beta">{{ i18n.ts.beta }}</span></template>
<template v-if="enableReactionsBuffering" #suffix>Enabled</template>
<template v-else #suffix>Disabled</template>
<template v-if="isRbtModified" #footer>
<MkButton primary rounded @click="saveRbt">{{ i18n.ts.save }}</MkButton>
</template>
<div class="_gaps_m">
<MkSwitch v-model="enableReactionsBuffering">
@@ -95,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import { ref, computed, watch } from 'vue';
import XHeader from './_header_.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os.js';
@@ -107,6 +113,7 @@ import MkSwitch from '@/components/MkSwitch.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkInput from '@/components/MkInput.vue';
import MkLink from '@/components/MkLink.vue';
import MkButton from '@/components/MkButton.vue';
const enableServerMachineStats = ref<boolean>(false);
const enableIdenticonGeneration = ref<boolean>(false);
@@ -120,6 +127,10 @@ const perUserHomeTimelineCacheMax = ref<number>(0);
const perUserListTimelineCacheMax = ref<number>(0);
const enableReactionsBuffering = ref<boolean>(false);
const isFttModified = ref<boolean>(false);
const isRbtModified = ref<boolean>(false);
async function init() {
const meta = await misskeyApi('admin/meta');
enableServerMachineStats.value = meta.enableServerMachineStats;
@@ -133,32 +144,72 @@ async function init() {
perUserHomeTimelineCacheMax.value = meta.perUserHomeTimelineCacheMax;
perUserListTimelineCacheMax.value = meta.perUserListTimelineCacheMax;
enableReactionsBuffering.value = meta.enableReactionsBuffering;
watch([enableFanoutTimeline, enableFanoutTimelineDbFallback, perLocalUserUserTimelineCacheMax, perRemoteUserUserTimelineCacheMax, perUserHomeTimelineCacheMax, perUserListTimelineCacheMax], () => {
isFttModified.value = true;
});
watch(enableReactionsBuffering, () => {
isRbtModified.value = true;
});
}
function save() {
function onChange_enableServerMachineStats(value: boolean) {
os.apiWithDialog('admin/update-meta', {
enableServerMachineStats: value,
}).then(() => {
fetchInstance(true);
});
}
function onChange_enableIdenticonGeneration(value: boolean) {
os.apiWithDialog('admin/update-meta', {
enableIdenticonGeneration: value,
}).then(() => {
fetchInstance(true);
});
}
function onChange_enableChartsForRemoteUser(value: boolean) {
os.apiWithDialog('admin/update-meta', {
enableChartsForRemoteUser: value,
}).then(() => {
fetchInstance(true);
});
}
function onChange_enableChartsForFederatedInstances(value: boolean) {
os.apiWithDialog('admin/update-meta', {
enableChartsForFederatedInstances: value,
}).then(() => {
fetchInstance(true);
});
}
function saveFtt() {
os.apiWithDialog('admin/update-meta', {
enableServerMachineStats: enableServerMachineStats.value,
enableIdenticonGeneration: enableIdenticonGeneration.value,
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
enableFanoutTimeline: enableFanoutTimeline.value,
enableFanoutTimelineDbFallback: enableFanoutTimelineDbFallback.value,
perLocalUserUserTimelineCacheMax: perLocalUserUserTimelineCacheMax.value,
perRemoteUserUserTimelineCacheMax: perRemoteUserUserTimelineCacheMax.value,
perUserHomeTimelineCacheMax: perUserHomeTimelineCacheMax.value,
perUserListTimelineCacheMax: perUserListTimelineCacheMax.value,
enableReactionsBuffering: enableReactionsBuffering.value,
}).then(() => {
isFttModified.value = false;
fetchInstance(true);
});
}
const headerActions = computed(() => [{
asFullButton: true,
icon: 'ti ti-check',
text: i18n.ts.save,
handler: save,
}]);
function saveRbt() {
os.apiWithDialog('admin/update-meta', {
enableReactionsBuffering: enableReactionsBuffering.value,
}).then(() => {
isRbtModified.value = false;
fetchInstance(true);
});
}
const headerActions = computed(() => []);
const headerTabs = computed(() => []);

View File

@@ -1,71 +0,0 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
<FormSuspense :p="init">
<MkInfo>{{ i18n.ts.proxyAccountDescription }}</MkInfo>
<MkKeyValue>
<template #key>{{ i18n.ts.proxyAccount }}</template>
<template #value>{{ proxyAccount ? `@${proxyAccount.username}` : i18n.ts.none }}</template>
</MkKeyValue>
<MkButton primary @click="chooseProxyAccount">{{ i18n.ts.selectAccount }}</MkButton>
</FormSuspense>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import * as Misskey from 'misskey-js';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkButton from '@/components/MkButton.vue';
import MkInfo from '@/components/MkInfo.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const proxyAccount = ref<Misskey.entities.UserDetailed | null>(null);
const proxyAccountId = ref<string | null>(null);
async function init() {
const meta = await misskeyApi('admin/meta');
proxyAccountId.value = meta.proxyAccountId;
if (proxyAccountId.value) {
proxyAccount.value = await misskeyApi('users/show', { userId: proxyAccountId.value });
}
}
function chooseProxyAccount() {
os.selectUser({ localOnly: true }).then(user => {
proxyAccount.value = user;
proxyAccountId.value = user.id;
save();
});
}
function save() {
os.apiWithDialog('admin/update-meta', {
proxyAccountId: proxyAccountId.value,
}).then(() => {
fetchInstance(true);
});
}
const headerActions = computed(() => []);
const headerTabs = computed(() => []);
definePageMetadata(() => ({
title: i18n.ts.proxyAccount,
icon: 'ti ti-ghost',
}));
</script>

View File

@@ -11,6 +11,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps">
<MkFolder>
<template #label>{{ i18n.ts._role.baseRole }}</template>
<template #footer>
<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton>
</template>
<div class="_gaps_s">
<MkInput v-model="baseRoleQ" type="search">
<template #prefix><i class="ti ti-search"></i></template>
@@ -253,8 +256,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.enable }}</template>
</MkSwitch>
</MkFolder>
<MkButton primary rounded @click="updateBaseRole">{{ i18n.ts.save }}</MkButton>
</div>
</MkFolder>
<MkButton primary rounded @click="create"><i class="ti ti-plus"></i> {{ i18n.ts._role.new }}</MkButton>
@@ -280,6 +281,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, reactive, ref } from 'vue';
import { ROLE_POLICIES } from '@@/js/const.js';
import XHeader from './_header_.vue';
import MkInput from '@/components/MkInput.vue';
import MkFolder from '@/components/MkFolder.vue';
@@ -293,7 +295,6 @@ import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { instance, fetchInstance } from '@/instance.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { ROLE_POLICIES } from '@@/js/const.js';
import { useRouter } from '@/router/supplier.js';
const router = useRouter();

View File

@@ -10,55 +10,93 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
<FormSuspense :p="init">
<div class="_gaps_m">
<MkInput v-model="name">
<template #label>{{ i18n.ts.instanceName }}</template>
</MkInput>
<MkFolder :defaultOpen="true">
<template #icon><i class="ti ti-info-circle"></i></template>
<template #label>{{ i18n.ts.info }}</template>
<template #footer>
<MkButton primary rounded @click="saveInfo">{{ i18n.ts.save }}</MkButton>
</template>
<MkInput v-model="shortName">
<template #label>{{ i18n.ts._serverSettings.shortName }} ({{ i18n.ts.optional }})</template>
<template #caption>{{ i18n.ts._serverSettings.shortNameDescription }}</template>
</MkInput>
<div class="_gaps">
<MkInput v-model="name">
<template #label>{{ i18n.ts.instanceName }}</template>
</MkInput>
<MkTextarea v-model="description">
<template #label>{{ i18n.ts.instanceDescription }}</template>
</MkTextarea>
<MkInput v-model="shortName">
<template #label>{{ i18n.ts._serverSettings.shortName }} ({{ i18n.ts.optional }})</template>
<template #caption>{{ i18n.ts._serverSettings.shortNameDescription }}</template>
</MkInput>
<FormSplit :minWidth="300">
<MkInput v-model="maintainerName">
<template #label>{{ i18n.ts.maintainerName }}</template>
</MkInput>
<MkTextarea v-model="description">
<template #label>{{ i18n.ts.instanceDescription }}</template>
</MkTextarea>
<MkInput v-model="maintainerEmail" type="email">
<template #prefix><i class="ti ti-mail"></i></template>
<template #label>{{ i18n.ts.maintainerEmail }}</template>
</MkInput>
</FormSplit>
<FormSplit :minWidth="300">
<MkInput v-model="maintainerName">
<template #label>{{ i18n.ts.maintainerName }}</template>
</MkInput>
<MkInput v-model="repositoryUrl" type="url">
<template #label>{{ i18n.ts.repositoryUrl }}</template>
<template #prefix><i class="ti ti-link"></i></template>
<template #caption>{{ i18n.ts.repositoryUrlDescription }}</template>
</MkInput>
<MkInput v-model="maintainerEmail" type="email">
<template #prefix><i class="ti ti-mail"></i></template>
<template #label>{{ i18n.ts.maintainerEmail }}</template>
</MkInput>
</FormSplit>
<MkInfo v-if="!instance.providesTarball && !repositoryUrl" warn>
{{ i18n.ts.repositoryUrlOrTarballRequired }}
</MkInfo>
<MkInput v-model="tosUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.tosUrl }}</template>
</MkInput>
<MkInput v-model="impressumUrl" type="url">
<template #label>{{ i18n.ts.impressumUrl }}</template>
<template #prefix><i class="ti ti-link"></i></template>
<template #caption>{{ i18n.ts.impressumDescription }}</template>
</MkInput>
<MkInput v-model="privacyPolicyUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.privacyPolicyUrl }}</template>
</MkInput>
<MkTextarea v-model="pinnedUsers">
<MkInput v-model="inquiryUrl" type="url">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts._serverSettings.inquiryUrl }}</template>
<template #caption>{{ i18n.ts._serverSettings.inquiryUrlDescription }}</template>
</MkInput>
<MkInput v-model="repositoryUrl" type="url">
<template #label>{{ i18n.ts.repositoryUrl }}</template>
<template #prefix><i class="ti ti-link"></i></template>
<template #caption>{{ i18n.ts.repositoryUrlDescription }}</template>
</MkInput>
<MkInfo v-if="!instance.providesTarball && !repositoryUrl" warn>
{{ i18n.ts.repositoryUrlOrTarballRequired }}
</MkInfo>
<MkInput v-model="impressumUrl" type="url">
<template #label>{{ i18n.ts.impressumUrl }}</template>
<template #prefix><i class="ti ti-link"></i></template>
<template #caption>{{ i18n.ts.impressumDescription }}</template>
</MkInput>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-user-star"></i></template>
<template #label>{{ i18n.ts.pinnedUsers }}</template>
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
</MkTextarea>
<template #footer>
<MkButton primary rounded @click="save_pinnedUsers">{{ i18n.ts.save }}</MkButton>
</template>
<FormSection>
<MkTextarea v-model="pinnedUsers">
<template #label>{{ i18n.ts.pinnedUsers }}</template>
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
</MkTextarea>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-cloud"></i></template>
<template #label>{{ i18n.ts.files }}</template>
<template #footer>
<MkButton primary rounded @click="saveFiles">{{ i18n.ts.save }}</MkButton>
</template>
<div class="_gaps_m">
<div class="_gaps">
<MkSwitch v-model="cacheRemoteFiles">
<template #label>{{ i18n.ts.cacheRemoteFiles }}</template>
<template #caption>{{ i18n.ts.cacheRemoteFilesDescription }}{{ i18n.ts.youCanCleanRemoteFilesCache }}</template>
@@ -71,12 +109,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSwitch>
</template>
</div>
</FormSection>
</MkFolder>
<FormSection>
<MkFolder>
<template #icon><i class="ti ti-world-cog"></i></template>
<template #label>ServiceWorker</template>
<template #footer>
<MkButton primary rounded @click="saveServiceWorker">{{ i18n.ts.save }}</MkButton>
</template>
<div class="_gaps_m">
<div class="_gaps">
<MkSwitch v-model="enableServiceWorker">
<template #label>{{ i18n.ts.enableServiceworker }}</template>
<template #caption>{{ i18n.ts.serviceworkerInfo }}</template>
@@ -94,12 +136,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInput>
</template>
</div>
</FormSection>
</MkFolder>
<FormSection>
<MkFolder>
<template #icon><i class="ti ti-ad"></i></template>
<template #label>{{ i18n.ts._ad.adsSettings }}</template>
<template #footer>
<MkButton primary rounded @click="saveAd">{{ i18n.ts.save }}</MkButton>
</template>
<div class="_gaps_m">
<div class="_gaps">
<div class="_gaps_s">
<MkInput v-model="notesPerOneAd" :min="0" type="number">
<template #label>{{ i18n.ts._ad.notesPerOneAd }}</template>
@@ -110,12 +156,16 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkInfo>
</div>
</div>
</FormSection>
</MkFolder>
<FormSection>
<MkFolder>
<template #icon><i class="ti ti-world-search"></i></template>
<template #label>{{ i18n.ts._urlPreviewSetting.title }}</template>
<template #footer>
<MkButton primary rounded @click="saveUrlPreview">{{ i18n.ts.save }}</MkButton>
</template>
<div class="_gaps_m">
<div class="_gaps">
<MkSwitch v-model="urlPreviewEnabled">
<template #label>{{ i18n.ts._urlPreviewSetting.enable }}</template>
</MkSwitch>
@@ -157,29 +207,37 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
</div>
</FormSection>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-ghost"></i></template>
<template #label>{{ i18n.ts.proxyAccount }}</template>
<div class="_gaps">
<MkInfo>{{ i18n.ts.proxyAccountDescription }}</MkInfo>
<MkKeyValue>
<template #key>{{ i18n.ts.proxyAccount }}</template>
<template #value>{{ proxyAccount ? `@${proxyAccount.username}` : i18n.ts.none }}</template>
</MkKeyValue>
<MkButton primary @click="chooseProxyAccount">{{ i18n.ts.selectAccount }}</MkButton>
</div>
</MkFolder>
</div>
</FormSuspense>
</MkSpacer>
<template #footer>
<div :class="$style.footer">
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
<MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
</MkSpacer>
</div>
</template>
</MkStickyContainer>
</div>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
import * as Misskey from 'misskey-js';
import XHeader from './_header_.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkInfo from '@/components/MkInfo.vue';
import FormSection from '@/components/form/section.vue';
import FormSplit from '@/components/form/split.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os.js';
@@ -190,12 +248,18 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
const proxyAccount = ref<Misskey.entities.UserDetailed | null>(null);
const name = ref<string | null>(null);
const shortName = ref<string | null>(null);
const description = ref<string | null>(null);
const maintainerName = ref<string | null>(null);
const maintainerEmail = ref<string | null>(null);
const tosUrl = ref<string | null>(null);
const privacyPolicyUrl = ref<string | null>(null);
const inquiryUrl = ref<string | null>(null);
const repositoryUrl = ref<string | null>(null);
const impressumUrl = ref<string | null>(null);
const pinnedUsers = ref<string>('');
@@ -211,6 +275,7 @@ const urlPreviewMaximumContentLength = ref<number>(1024 * 1024 * 10);
const urlPreviewRequireContentLength = ref<boolean>(true);
const urlPreviewUserAgent = ref<string | null>(null);
const urlPreviewSummaryProxyUrl = ref<string | null>(null);
const proxyAccountId = ref<string | null>(null);
async function init(): Promise<void> {
const meta = await misskeyApi('admin/meta');
@@ -219,6 +284,9 @@ async function init(): Promise<void> {
description.value = meta.description;
maintainerName.value = meta.maintainerName;
maintainerEmail.value = meta.maintainerEmail;
tosUrl.value = meta.tosUrl;
privacyPolicyUrl.value = meta.privacyPolicyUrl;
inquiryUrl.value = meta.inquiryUrl;
repositoryUrl.value = meta.repositoryUrl;
impressumUrl.value = meta.impressumUrl;
pinnedUsers.value = meta.pinnedUsers.join('\n');
@@ -234,33 +302,91 @@ async function init(): Promise<void> {
urlPreviewRequireContentLength.value = meta.urlPreviewRequireContentLength;
urlPreviewUserAgent.value = meta.urlPreviewUserAgent;
urlPreviewSummaryProxyUrl.value = meta.urlPreviewSummaryProxyUrl;
proxyAccountId.value = meta.proxyAccountId;
if (proxyAccountId.value) {
proxyAccount.value = await misskeyApi('users/show', { userId: proxyAccountId.value });
}
}
async function save() {
await os.apiWithDialog('admin/update-meta', {
function saveInfo() {
os.apiWithDialog('admin/update-meta', {
name: name.value,
shortName: shortName.value === '' ? null : shortName.value,
description: description.value,
maintainerName: maintainerName.value,
maintainerEmail: maintainerEmail.value,
tosUrl: tosUrl.value,
privacyPolicyUrl: privacyPolicyUrl.value,
inquiryUrl: inquiryUrl.value,
repositoryUrl: repositoryUrl.value,
impressumUrl: impressumUrl.value,
}).then(() => {
fetchInstance(true);
});
}
function save_pinnedUsers() {
os.apiWithDialog('admin/update-meta', {
pinnedUsers: pinnedUsers.value.split('\n'),
}).then(() => {
fetchInstance(true);
});
}
function saveFiles() {
os.apiWithDialog('admin/update-meta', {
cacheRemoteFiles: cacheRemoteFiles.value,
cacheRemoteSensitiveFiles: cacheRemoteSensitiveFiles.value,
}).then(() => {
fetchInstance(true);
});
}
function saveServiceWorker() {
os.apiWithDialog('admin/update-meta', {
enableServiceWorker: enableServiceWorker.value,
swPublicKey: swPublicKey.value,
swPrivateKey: swPrivateKey.value,
}).then(() => {
fetchInstance(true);
});
}
function saveAd() {
os.apiWithDialog('admin/update-meta', {
notesPerOneAd: notesPerOneAd.value,
}).then(() => {
fetchInstance(true);
});
}
function saveUrlPreview() {
os.apiWithDialog('admin/update-meta', {
urlPreviewEnabled: urlPreviewEnabled.value,
urlPreviewTimeout: urlPreviewTimeout.value,
urlPreviewMaximumContentLength: urlPreviewMaximumContentLength.value,
urlPreviewRequireContentLength: urlPreviewRequireContentLength.value,
urlPreviewUserAgent: urlPreviewUserAgent.value,
urlPreviewSummaryProxyUrl: urlPreviewSummaryProxyUrl.value,
}).then(() => {
fetchInstance(true);
});
}
fetchInstance(true);
function chooseProxyAccount() {
os.selectUser({ localOnly: true }).then(user => {
proxyAccount.value = user;
proxyAccountId.value = user.id;
saveProxyAccount();
});
}
function saveProxyAccount() {
os.apiWithDialog('admin/update-meta', {
proxyAccountId: proxyAccountId.value,
}).then(() => {
fetchInstance(true);
});
}
const headerTabs = computed(() => []);
@@ -272,11 +398,6 @@ definePageMetadata(() => ({
</script>
<style lang="scss" module>
.footer {
-webkit-backdrop-filter: var(--blur, blur(15px));
backdrop-filter: var(--blur, blur(15px));
}
.subCaption {
font-size: 0.85em;
color: var(--fgTransparentWeak);

View File

@@ -462,22 +462,14 @@ const routes: RouteDef[] = [{
path: '/relays',
name: 'relays',
component: page(() => import('@/pages/admin/relays.vue')),
}, {
path: '/instance-block',
name: 'instance-block',
component: page(() => import('@/pages/admin/instance-block.vue')),
}, {
path: '/proxy-account',
name: 'proxy-account',
component: page(() => import('@/pages/admin/proxy-account.vue')),
}, {
path: '/external-services',
name: 'external-services',
component: page(() => import('@/pages/admin/external-services.vue')),
}, {
path: '/other-settings',
name: 'other-settings',
component: page(() => import('@/pages/admin/other-settings.vue')),
path: '/performance',
name: 'performance',
component: page(() => import('@/pages/admin/performance.vue')),
}, {
path: '/server-rules',
name: 'server-rules',

View File

@@ -1,7 +1,7 @@
{
"type": "module",
"name": "misskey-js",
"version": "2024.9.0-alpha.3",
"version": "2024.9.0-alpha.5",
"description": "Misskey SDK for JavaScript",
"license": "MIT",
"main": "./built/index.js",