refactor(frontend): フロントエンドの型エラー解消(途中まで) (#16539)
* fix(frontend): FormLinkをボタンとして使用した際にエラーが出る問題を修正 * refactor(frontend): フロントエンドの型エラー解消 * remove unused ts-expect-error * migrate * remove unrelated changes * fix lint * more type fixes
This commit is contained in:
parent
c174c5c144
commit
5b4115e21a
|
@ -34,13 +34,22 @@ export const meta = {
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
ref: 'MeDetailed',
|
allOf: [
|
||||||
properties: {
|
{
|
||||||
token: {
|
type: 'object',
|
||||||
type: 'string',
|
ref: 'MeDetailed',
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
token: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|
|
@ -22,17 +22,26 @@ export const meta = {
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
ref: 'UserList',
|
allOf: [
|
||||||
properties: {
|
{
|
||||||
likedCount: {
|
type: 'object',
|
||||||
type: 'number',
|
ref: 'UserList',
|
||||||
optional: true, nullable: false,
|
|
||||||
},
|
},
|
||||||
isLiked: {
|
{
|
||||||
type: 'boolean',
|
type: 'object',
|
||||||
optional: true, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
likedCount: {
|
||||||
|
type: 'number',
|
||||||
|
optional: true, nullable: false,
|
||||||
|
},
|
||||||
|
isLiked: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: true, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
errors: {
|
errors: {
|
||||||
|
|
|
@ -68,7 +68,6 @@ async function createAdmin(host: Host): Promise<Misskey.entities.SignupResponse
|
||||||
return await client.request('admin/accounts/create', ADMIN_PARAMS).then(res => {
|
return await client.request('admin/accounts/create', ADMIN_PARAMS).then(res => {
|
||||||
ADMIN_CACHE.set(host, {
|
ADMIN_CACHE.set(host, {
|
||||||
id: res.id,
|
id: res.id,
|
||||||
// @ts-expect-error FIXME: openapi-typescript generates incorrect response type for this endpoint, so ignore this
|
|
||||||
i: res.token,
|
i: res.token,
|
||||||
});
|
});
|
||||||
return res as Misskey.entities.SignupResponse;
|
return res as Misskey.entities.SignupResponse;
|
||||||
|
|
|
@ -29,6 +29,6 @@ const users = ref<Misskey.entities.UserLite[]>([]);
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
users.value = await misskeyApi('users/show', {
|
users.value = await misskeyApi('users/show', {
|
||||||
userIds: props.userIds,
|
userIds: props.userIds,
|
||||||
}) as unknown as Misskey.entities.UserLite[];
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -823,17 +823,15 @@ async function saveServerDraft(clearLocal = false) {
|
||||||
return await os.apiWithDialog(serverDraftId.value == null ? 'notes/drafts/create' : 'notes/drafts/update', {
|
return await os.apiWithDialog(serverDraftId.value == null ? 'notes/drafts/create' : 'notes/drafts/update', {
|
||||||
...(serverDraftId.value == null ? {} : { draftId: serverDraftId.value }),
|
...(serverDraftId.value == null ? {} : { draftId: serverDraftId.value }),
|
||||||
text: text.value,
|
text: text.value,
|
||||||
useCw: useCw.value,
|
cw: useCw.value ? cw.value || null : null,
|
||||||
cw: cw.value,
|
|
||||||
visibility: visibility.value,
|
visibility: visibility.value,
|
||||||
localOnly: localOnly.value,
|
localOnly: localOnly.value,
|
||||||
hashtag: hashtags.value,
|
hashtag: hashtags.value,
|
||||||
...(files.value.length > 0 ? { fileIds: files.value.map(f => f.id) } : {}),
|
...(files.value.length > 0 ? { fileIds: files.value.map(f => f.id) } : {}),
|
||||||
poll: poll.value,
|
poll: poll.value,
|
||||||
...(visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
|
...(visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
|
||||||
renoteId: renoteTargetNote.value ? renoteTargetNote.value.id : undefined,
|
renoteId: renoteTargetNote.value ? renoteTargetNote.value.id : quoteId.value ? quoteId.value : undefined,
|
||||||
replyId: replyTargetNote.value ? replyTargetNote.value.id : undefined,
|
replyId: replyTargetNote.value ? replyTargetNote.value.id : undefined,
|
||||||
quoteId: quoteId.value,
|
|
||||||
channelId: targetChannel.value ? targetChannel.value.id : undefined,
|
channelId: targetChannel.value ? targetChannel.value.id : undefined,
|
||||||
reactionAcceptance: reactionAcceptance.value,
|
reactionAcceptance: reactionAcceptance.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
|
@ -90,7 +90,7 @@ function subscribe() {
|
||||||
publickey: encode(subscription.getKey('p256dh')),
|
publickey: encode(subscription.getKey('p256dh')),
|
||||||
});
|
});
|
||||||
}, async err => { // When subscribe failed
|
}, async err => { // When subscribe failed
|
||||||
// 通知が許可されていなかったとき
|
// 通知が許可されていなかったとき
|
||||||
if (err?.name === 'NotAllowedError') {
|
if (err?.name === 'NotAllowedError') {
|
||||||
console.info('User denied the notification permission request.');
|
console.info('User denied the notification permission request.');
|
||||||
return;
|
return;
|
||||||
|
@ -114,14 +114,13 @@ async function unsubscribe() {
|
||||||
|
|
||||||
if ($i && accounts.length >= 2) {
|
if ($i && accounts.length >= 2) {
|
||||||
apiWithDialog('sw/unregister', {
|
apiWithDialog('sw/unregister', {
|
||||||
i: $i.token,
|
|
||||||
endpoint,
|
endpoint,
|
||||||
});
|
}, $i.token);
|
||||||
} else {
|
} else {
|
||||||
pushSubscription.value.unsubscribe();
|
pushSubscription.value.unsubscribe();
|
||||||
apiWithDialog('sw/unregister', {
|
apiWithDialog('sw/unregister', {
|
||||||
endpoint,
|
endpoint,
|
||||||
});
|
}, null);
|
||||||
pushSubscription.value = null;
|
pushSubscription.value = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,7 +133,7 @@ function encode(buffer: ArrayBuffer | null) {
|
||||||
* Convert the URL safe base64 string to a Uint8Array
|
* Convert the URL safe base64 string to a Uint8Array
|
||||||
* @param base64String base64 string
|
* @param base64String base64 string
|
||||||
*/
|
*/
|
||||||
function urlBase64ToUint8Array(base64String: string): Uint8Array {
|
function urlBase64ToUint8Array(base64String: string): BufferSource {
|
||||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||||
const base64 = (base64String + padding)
|
const base64 = (base64String + padding)
|
||||||
.replace(/-/g, '+')
|
.replace(/-/g, '+')
|
||||||
|
|
|
@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template>
|
<template>
|
||||||
<MkA :to="forModeration ? `/admin/roles/${role.id}` : `/roles/${role.id}`" :class="$style.root" tabindex="-1" :style="{ '--color': role.color }">
|
<MkA :to="forModeration ? `/admin/roles/${role.id}` : `/roles/${role.id}`" :class="$style.root" tabindex="-1" :style="{ '--color': role.color }">
|
||||||
<template v-if="forModeration">
|
<template v-if="forModeration">
|
||||||
<i v-if="role.isPublic" class="ti ti-world" :class="$style.icon" style="color: var(--MI_THEME-success)"></i>
|
<i v-if="'isPublic' in role && role.isPublic" class="ti ti-world" :class="$style.icon" style="color: var(--MI_THEME-success)"></i>
|
||||||
<i v-else class="ti ti-lock" :class="$style.icon" style="color: var(--MI_THEME-warn)"></i>
|
<i v-else class="ti ti-lock" :class="$style.icon" style="color: var(--MI_THEME-warn)"></i>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
</span>
|
</span>
|
||||||
<span :class="$style.bodyName">{{ role.name }}</span>
|
<span :class="$style.bodyName">{{ role.name }}</span>
|
||||||
<template v-if="detailed">
|
<template v-if="detailed && 'target' in role && 'usersCount' in role">
|
||||||
<span v-if="role.target === 'manual'" :class="$style.bodyUsers">{{ role.usersCount }} users</span>
|
<span v-if="role.target === 'manual'" :class="$style.bodyUsers">{{ role.usersCount }} users</span>
|
||||||
<span v-else-if="role.target === 'conditional'" :class="$style.bodyUsers">? users</span>
|
<span v-else-if="role.target === 'conditional'" :class="$style.bodyUsers">? users</span>
|
||||||
</template>
|
</template>
|
||||||
|
@ -39,7 +39,7 @@ import * as Misskey from 'misskey-js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
role: Misskey.entities.Role;
|
role: Misskey.entities.Role | Misskey.entities.IResponse['roles'][number];
|
||||||
forModeration: boolean;
|
forModeration: boolean;
|
||||||
detailed?: boolean;
|
detailed?: boolean;
|
||||||
}>(), {
|
}>(), {
|
||||||
|
|
|
@ -72,7 +72,7 @@ import { getStaticImageUrl } from '@/utility/media-proxy.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
showing: boolean;
|
showing: boolean;
|
||||||
q: string;
|
q: string | Misskey.entities.UserDetailed;
|
||||||
source: HTMLElement;
|
source: HTMLElement;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
@ -99,10 +99,11 @@ async function fetchUser() {
|
||||||
user.value = props.q;
|
user.value = props.q;
|
||||||
error.value = false;
|
error.value = false;
|
||||||
} else {
|
} else {
|
||||||
const query: Omit<Misskey.entities.UsersShowRequest, 'userIds'> = props.q.startsWith('@') ?
|
const query: Misskey.entities.UsersShowRequest = props.q.startsWith('@') ?
|
||||||
Misskey.acct.parse(props.q.substring(1)) :
|
Misskey.acct.parse(props.q.substring(1)) :
|
||||||
{ userId: props.q };
|
{ userId: props.q };
|
||||||
|
|
||||||
|
// @ts-expect-error payloadの引数側の型が正常に解決されない
|
||||||
misskeyApi('users/show', query).then(res => {
|
misskeyApi('users/show', query).then(res => {
|
||||||
if (!props.showing) return;
|
if (!props.showing) return;
|
||||||
user.value = res;
|
user.value = res;
|
||||||
|
|
|
@ -4,31 +4,39 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div :class="[$style.root, { [$style.inline]: inline }]">
|
<component
|
||||||
<a v-if="external" :class="$style.main" class="_button" :href="to" target="_blank">
|
:is="to ? 'div' : 'button'"
|
||||||
|
:class="[
|
||||||
|
$style.root,
|
||||||
|
{
|
||||||
|
[$style.inline]: inline,
|
||||||
|
'_button': !to,
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="to ? (external ? 'a' : 'MkA') : 'div'"
|
||||||
|
:class="[$style.main, { [$style.active]: active }]"
|
||||||
|
class="_button"
|
||||||
|
v-bind="to ? (external ? { href: to, target: '_blank' } : { to, behavior }) : {}"
|
||||||
|
>
|
||||||
<span :class="$style.icon"><slot name="icon"></slot></span>
|
<span :class="$style.icon"><slot name="icon"></slot></span>
|
||||||
<span :class="$style.text"><slot></slot></span>
|
<div :class="$style.headerText">
|
||||||
|
<div>
|
||||||
|
<MkCondensedLine :minScale="2 / 3"><slot></slot></MkCondensedLine>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<span :class="$style.suffix">
|
<span :class="$style.suffix">
|
||||||
<span :class="$style.suffixText"><slot name="suffix"></slot></span>
|
<span :class="$style.suffixText"><slot name="suffix"></slot></span>
|
||||||
<i class="ti ti-external-link"></i>
|
<i :class="to && external ? 'ti ti-external-link' : 'ti ti-chevron-right'"></i>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</component>
|
||||||
<MkA v-else :class="[$style.main, { [$style.active]: active }]" class="_button" :to="to" :behavior="behavior">
|
</component>
|
||||||
<span :class="$style.icon"><slot name="icon"></slot></span>
|
|
||||||
<span :class="$style.text"><slot></slot></span>
|
|
||||||
<span :class="$style.suffix">
|
|
||||||
<span :class="$style.suffixText"><slot name="suffix"></slot></span>
|
|
||||||
<i class="ti ti-chevron-right"></i>
|
|
||||||
</span>
|
|
||||||
</MkA>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { } from 'vue';
|
defineProps<{
|
||||||
|
to?: string;
|
||||||
const props = defineProps<{
|
|
||||||
to: string;
|
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
external?: boolean;
|
external?: boolean;
|
||||||
behavior?: null | 'window' | 'browser';
|
behavior?: null | 'window' | 'browser';
|
||||||
|
@ -75,17 +83,18 @@ const props = defineProps<{
|
||||||
&:empty {
|
&:empty {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
& + .text {
|
& + .headerText {
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.headerText {
|
||||||
flex-shrink: 1;
|
white-space: nowrap;
|
||||||
white-space: normal;
|
text-overflow: ellipsis;
|
||||||
|
text-align: start;
|
||||||
|
overflow: hidden;
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.suffix {
|
.suffix {
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPageHeader v-else v-model:tab="tab" v-bind="pageHeaderProps"/>
|
<MkPageHeader v-else v-model:tab="tab" v-bind="pageHeaderProps"/>
|
||||||
</template>
|
</template>
|
||||||
<div :class="$style.body">
|
<div :class="$style.body">
|
||||||
<MkSwiper v-if="prefer.s.enableHorizontalSwipe && swipable && (props.tabs?.length ?? 1) > 1" v-model:tab="tab" :class="$style.swiper" :tabs="props.tabs">
|
<MkSwiper v-if="prefer.s.enableHorizontalSwipe && swipable && (props.tabs?.length ?? 1) > 1" v-model:tab="tab" :class="$style.swiper" :tabs="props.tabs ?? []">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</MkSwiper>
|
</MkSwiper>
|
||||||
<slot v-else></slot>
|
<slot v-else></slot>
|
||||||
|
@ -45,7 +45,7 @@ const props = withDefaults(defineProps<PageHeaderProps & {
|
||||||
});
|
});
|
||||||
|
|
||||||
const pageHeaderProps = computed(() => {
|
const pageHeaderProps = computed(() => {
|
||||||
const { reversed, ...rest } = props;
|
const { reversed, tab, ...rest } = props;
|
||||||
return rest;
|
return rest;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -75,10 +75,6 @@ defineExpose({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.root {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.body, .swiper {
|
.body, .swiper {
|
||||||
min-height: calc(100cqh - (var(--MI-stickyTop, 0px) + var(--MI-stickyBottom, 0px)));
|
min-height: calc(100cqh - (var(--MI-stickyTop, 0px) + var(--MI-stickyBottom, 0px)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ export const globalEvents = new EventEmitter<Events>();
|
||||||
|
|
||||||
export function useGlobalEvent<T extends keyof Events>(
|
export function useGlobalEvent<T extends keyof Events>(
|
||||||
event: T,
|
event: T,
|
||||||
callback: Events[T],
|
callback: EventEmitter.EventListener<Events, T>,
|
||||||
): void {
|
): void {
|
||||||
globalEvents.on(event, callback);
|
globalEvents.on(event, callback);
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|
|
@ -94,7 +94,7 @@ export class Pizzax<T extends StateDef> {
|
||||||
|
|
||||||
private mergeState<X>(value: X, def: X): X {
|
private mergeState<X>(value: X, def: X): X {
|
||||||
if (this.isPureObject(value) && this.isPureObject(def)) {
|
if (this.isPureObject(value) && this.isPureObject(def)) {
|
||||||
const merged = deepMerge(value, def);
|
const merged = deepMerge<Record<PropertyKey, unknown>>(value, def);
|
||||||
|
|
||||||
if (_DEV_) console.log('Merging state. Incoming: ', value, ' Default: ', def, ' Result: ', merged);
|
if (_DEV_) console.log('Merging state. Incoming: ', value, ' Default: ', def, ' Result: ', merged);
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,9 @@ import { focusParent } from '@/utility/focus.js';
|
||||||
export const openingWindowsCount = ref(0);
|
export const openingWindowsCount = ref(0);
|
||||||
|
|
||||||
export type ApiWithDialogCustomErrors = Record<string, { title?: string; text: string; }>;
|
export type ApiWithDialogCustomErrors = Record<string, { title?: string; text: string; }>;
|
||||||
export const apiWithDialog = (<E extends keyof Misskey.Endpoints, P extends Misskey.Endpoints[E]['req'] = Misskey.Endpoints[E]['req']>(
|
export const apiWithDialog = (<E extends keyof Misskey.Endpoints>(
|
||||||
endpoint: E,
|
endpoint: E,
|
||||||
data: P,
|
data: Misskey.Endpoints[E]['req'],
|
||||||
token?: string | null | undefined,
|
token?: string | null | undefined,
|
||||||
customErrors?: ApiWithDialogCustomErrors,
|
customErrors?: ApiWithDialogCustomErrors,
|
||||||
) => {
|
) => {
|
||||||
|
|
|
@ -11,12 +11,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkInput v-model="q" class="" :placeholder="i18n.ts.search" autocapitalize="off">
|
<MkInput v-model="q" class="" :placeholder="i18n.ts.search" autocapitalize="off">
|
||||||
<template #prefix><i class="ti ti-search"></i></template>
|
<template #prefix><i class="ti ti-search"></i></template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<!-- たくさんあると邪魔
|
|
||||||
<div class="tags">
|
|
||||||
<span class="tag _button" v-for="tag in customEmojiTags" :class="{ active: selectedTags.has(tag) }" @click="toggleTag(tag)">{{ tag }}</span>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MkFoldableSection v-if="searchEmojis">
|
<MkFoldableSection v-if="searchEmojis">
|
||||||
|
@ -42,51 +36,33 @@ import XEmoji from './emojis.emoji.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import { customEmojis, customEmojiCategories, getCustomEmojiTags } from '@/custom-emojis.js';
|
import { customEmojis, customEmojiCategories } from '@/custom-emojis.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
const customEmojiTags = getCustomEmojiTags();
|
|
||||||
const q = ref('');
|
const q = ref('');
|
||||||
const searchEmojis = ref<Misskey.entities.EmojiSimple[] | null>(null);
|
const searchEmojis = ref<Misskey.entities.EmojiSimple[] | null>(null);
|
||||||
const selectedTags = ref(new Set());
|
|
||||||
|
|
||||||
function search() {
|
function search() {
|
||||||
if ((q.value === '' || q.value == null) && selectedTags.value.size === 0) {
|
if (q.value === '' || q.value == null) {
|
||||||
searchEmojis.value = null;
|
searchEmojis.value = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedTags.value.size === 0) {
|
const queryarry = q.value.match(/\:([a-z0-9_]*)\:/g);
|
||||||
const queryarry = q.value.match(/\:([a-z0-9_]*)\:/g);
|
|
||||||
|
|
||||||
if (queryarry) {
|
if (queryarry) {
|
||||||
searchEmojis.value = customEmojis.value.filter(emoji =>
|
searchEmojis.value = customEmojis.value.filter(emoji =>
|
||||||
queryarry.includes(`:${emoji.name}:`),
|
queryarry.includes(`:${emoji.name}:`),
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
searchEmojis.value = customEmojis.value.filter(emoji => emoji.name.includes(q.value) || emoji.aliases.includes(q.value));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
searchEmojis.value = customEmojis.value.filter(emoji => (emoji.name.includes(q.value) || emoji.aliases.includes(q.value)) && [...selectedTags.value].every(t => emoji.aliases.includes(t)));
|
searchEmojis.value = customEmojis.value.filter(emoji => emoji.name.includes(q.value) || emoji.aliases.includes(q.value));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTag(tag) {
|
|
||||||
if (selectedTags.value.has(tag)) {
|
|
||||||
selectedTags.value.delete(tag);
|
|
||||||
} else {
|
|
||||||
selectedTags.value.add(tag);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(q, () => {
|
watch(q, () => {
|
||||||
search();
|
search();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(selectedTags, () => {
|
|
||||||
search();
|
|
||||||
}, { deep: true });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|
|
@ -59,7 +59,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
}, {
|
}, {
|
||||||
label: `${i18n.ts.registeredAt} (${i18n.ts.ascendingOrder})`,
|
label: `${i18n.ts.registeredAt} (${i18n.ts.ascendingOrder})`,
|
||||||
value: '-firstRetrievedAt',
|
value: '-firstRetrievedAt',
|
||||||
}] as const"
|
}]"
|
||||||
>
|
>
|
||||||
<template #label>{{ i18n.ts.sort }}</template>
|
<template #label>{{ i18n.ts.sort }}</template>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
|
|
|
@ -233,6 +233,7 @@ import { ensureSignin, iAmAdmin, iAmModerator } from '@/i.js';
|
||||||
import MkRolePreview from '@/components/MkRolePreview.vue';
|
import MkRolePreview from '@/components/MkRolePreview.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import { Paginator } from '@/utility/paginator.js';
|
import { Paginator } from '@/utility/paginator.js';
|
||||||
|
import type { ChartSrc } from '@/components/MkChart.vue';
|
||||||
|
|
||||||
const $i = ensureSignin();
|
const $i = ensureSignin();
|
||||||
|
|
||||||
|
@ -246,7 +247,7 @@ const props = withDefaults(defineProps<{
|
||||||
const result = await _fetch_();
|
const result = await _fetch_();
|
||||||
|
|
||||||
const tab = ref(props.initialTab);
|
const tab = ref(props.initialTab);
|
||||||
const chartSrc = ref('per-user-notes');
|
const chartSrc = ref<ChartSrc>('per-user-notes');
|
||||||
const user = ref(result.user);
|
const user = ref(result.user);
|
||||||
const info = ref(result.info);
|
const info = ref(result.info);
|
||||||
const ips = ref(result.ips);
|
const ips = ref(result.ips);
|
||||||
|
@ -429,7 +430,7 @@ async function assignRole() {
|
||||||
title: i18n.ts._role.chooseRoleToAssign,
|
title: i18n.ts._role.chooseRoleToAssign,
|
||||||
items: roles.map(r => ({ text: r.name, value: r.id })),
|
items: roles.map(r => ({ text: r.name, value: r.id })),
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled || roleId == null) return;
|
||||||
|
|
||||||
const { canceled: canceled2, result: period } = await os.select({
|
const { canceled: canceled2, result: period } = await os.select({
|
||||||
title: i18n.ts.period + ': ' + roles.find(r => r.id === roleId)!.name,
|
title: i18n.ts.period + ': ' + roles.find(r => r.id === roleId)!.name,
|
||||||
|
|
|
@ -303,8 +303,8 @@ async function onFileSelectClicked() {
|
||||||
const driveFiles = await chooseFileFromPcAndUpload({
|
const driveFiles = await chooseFileFromPcAndUpload({
|
||||||
multiple: true,
|
multiple: true,
|
||||||
folderId: selectedFolderId.value,
|
folderId: selectedFolderId.value,
|
||||||
// 拡張子は消す
|
// // 拡張子は消す
|
||||||
nameConverter: (file) => file.name.replace(/\.[a-zA-Z0-9]+$/, ''),
|
// nameConverter: (file) => file.name.replace(/\.[a-zA-Z0-9]+$/, ''),
|
||||||
});
|
});
|
||||||
|
|
||||||
gridItems.value.push(...driveFiles.map(fromDriveFile));
|
gridItems.value.push(...driveFiles.map(fromDriveFile));
|
||||||
|
|
|
@ -26,10 +26,10 @@ const chartEl = useTemplateRef('chartEl');
|
||||||
|
|
||||||
const { handler: externalTooltipHandler } = useChartTooltip();
|
const { handler: externalTooltipHandler } = useChartTooltip();
|
||||||
|
|
||||||
let chartInstance: Chart;
|
let chartInstance: Chart | null = null;
|
||||||
|
|
||||||
function setData(values) {
|
function setData(values) {
|
||||||
if (chartInstance == null) return;
|
if (chartInstance == null || chartInstance.data.labels == null) return;
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
chartInstance.data.labels.push('');
|
chartInstance.data.labels.push('');
|
||||||
chartInstance.data.datasets[0].data.push(value);
|
chartInstance.data.datasets[0].data.push(value);
|
||||||
|
@ -42,7 +42,7 @@ function setData(values) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushData(value) {
|
function pushData(value) {
|
||||||
if (chartInstance == null) return;
|
if (chartInstance == null || chartInstance.data.labels == null) return;
|
||||||
chartInstance.data.labels.push('');
|
chartInstance.data.labels.push('');
|
||||||
chartInstance.data.datasets[0].data.push(value);
|
chartInstance.data.datasets[0].data.push(value);
|
||||||
if (chartInstance.data.datasets[0].data.length > 200) {
|
if (chartInstance.data.datasets[0].data.length > 200) {
|
||||||
|
@ -69,6 +69,8 @@ const color =
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
|
if (chartEl.value == null) return;
|
||||||
|
|
||||||
chartInstance = new Chart(chartEl.value, {
|
chartInstance = new Chart(chartEl.value, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
|
|
|
@ -210,6 +210,7 @@ async function fetchCurrentQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchJobs() {
|
async function fetchJobs() {
|
||||||
|
if (tab.value === '-') return;
|
||||||
jobsFetching.value = true;
|
jobsFetching.value = true;
|
||||||
const state = jobState.value;
|
const state = jobState.value;
|
||||||
jobs.value = await misskeyApi('admin/queue/jobs', {
|
jobs.value = await misskeyApi('admin/queue/jobs', {
|
||||||
|
@ -307,6 +308,7 @@ async function removeJobs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshJob(jobId: string) {
|
async function refreshJob(jobId: string) {
|
||||||
|
if (tab.value === '-') return;
|
||||||
const newJob = await misskeyApi('admin/queue/show-job', { queue: tab.value, jobId });
|
const newJob = await misskeyApi('admin/queue/show-job', { queue: tab.value, jobId });
|
||||||
const index = jobs.value.findIndex((job) => job.id === jobId);
|
const index = jobs.value.findIndex((job) => job.id === jobId);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ initChart();
|
||||||
|
|
||||||
const chartEl = useTemplateRef('chartEl');
|
const chartEl = useTemplateRef('chartEl');
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
let chartInstance: Chart = null;
|
let chartInstance: Chart | null = null;
|
||||||
const chartLimit = 7;
|
const chartLimit = 7;
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="item _panel sub">
|
<div class="item _panel sub">
|
||||||
<div class="icon"><i class="ti ti-world-download"></i></div>
|
<div class="icon"><i class="ti ti-world-download"></i></div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="value">
|
<div v-if="federationSubActive != null" class="value">
|
||||||
{{ number(federationSubActive) }}
|
{{ number(federationSubActive) }}
|
||||||
<MkNumberDiff v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="federationSubActiveDiff"></MkNumberDiff>
|
<MkNumberDiff v-if="federationSubActiveDiff != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="federationSubActiveDiff"></MkNumberDiff>
|
||||||
</div>
|
</div>
|
||||||
<div class="label">Sub</div>
|
<div class="label">Sub</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,9 +33,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="item _panel pub">
|
<div class="item _panel pub">
|
||||||
<div class="icon"><i class="ti ti-world-upload"></i></div>
|
<div class="icon"><i class="ti ti-world-upload"></i></div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="value">
|
<div v-if="federationPubActive != null" class="value">
|
||||||
{{ number(federationPubActive) }}
|
{{ number(federationPubActive) }}
|
||||||
<MkNumberDiff v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="federationPubActiveDiff"></MkNumberDiff>
|
<MkNumberDiff v-if="federationPubActiveDiff != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="federationPubActiveDiff"></MkNumberDiff>
|
||||||
</div>
|
</div>
|
||||||
<div class="label">Pub</div>
|
<div class="label">Pub</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,8 +20,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import MkHeatmap from '@/components/MkHeatmap.vue';
|
import MkHeatmap from '@/components/MkHeatmap.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
import type { HeatmapSource } from '@/components/MkHeatmap.vue';
|
||||||
|
|
||||||
const src = ref('active-users');
|
const src = ref<HeatmapSource>('active-users');
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|
|
@ -32,15 +32,17 @@ const { handler: externalTooltipHandler } = useChartTooltip({
|
||||||
position: 'middle',
|
position: 'middle',
|
||||||
});
|
});
|
||||||
|
|
||||||
let chartInstance: Chart;
|
let chartInstance: Chart | null = null;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (chartEl.value == null) return;
|
||||||
|
|
||||||
chartInstance = new Chart(chartEl.value, {
|
chartInstance = new Chart(chartEl.value, {
|
||||||
type: 'doughnut',
|
type: 'doughnut',
|
||||||
data: {
|
data: {
|
||||||
labels: props.data.map(x => x.name),
|
labels: props.data.map(x => x.name),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
backgroundColor: props.data.map(x => x.color),
|
backgroundColor: props.data.map(x => x.color ?? '#000'),
|
||||||
borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'),
|
borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'),
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
hoverOffset: 0,
|
hoverOffset: 0,
|
||||||
|
@ -57,9 +59,10 @@ onMounted(() => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onClick: (ev) => {
|
onClick: (ev) => {
|
||||||
const hit = chartInstance.getElementsAtEventForMode(ev, 'nearest', { intersect: true }, false)[0];
|
if (ev.native == null) return;
|
||||||
if (hit && props.data[hit.index].onClick) {
|
const hit = chartInstance!.getElementsAtEventForMode(ev.native, 'nearest', { intersect: true }, false)[0];
|
||||||
props.data[hit.index].onClick();
|
if (hit && props.data[hit.index].onClick != null) {
|
||||||
|
props.data[hit.index].onClick!();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
|
|
|
@ -26,10 +26,10 @@ const chartEl = useTemplateRef('chartEl');
|
||||||
|
|
||||||
const { handler: externalTooltipHandler } = useChartTooltip();
|
const { handler: externalTooltipHandler } = useChartTooltip();
|
||||||
|
|
||||||
let chartInstance: Chart;
|
let chartInstance: Chart | null = null;
|
||||||
|
|
||||||
function setData(values) {
|
function setData(values: number[]) {
|
||||||
if (chartInstance == null) return;
|
if (chartInstance == null || chartInstance.data.labels == null) return;
|
||||||
for (const value of values) {
|
for (const value of values) {
|
||||||
chartInstance.data.labels.push('');
|
chartInstance.data.labels.push('');
|
||||||
chartInstance.data.datasets[0].data.push(value);
|
chartInstance.data.datasets[0].data.push(value);
|
||||||
|
@ -41,8 +41,8 @@ function setData(values) {
|
||||||
chartInstance.update();
|
chartInstance.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushData(value) {
|
function pushData(value: number) {
|
||||||
if (chartInstance == null) return;
|
if (chartInstance == null || chartInstance.data.labels == null) return;
|
||||||
chartInstance.data.labels.push('');
|
chartInstance.data.labels.push('');
|
||||||
chartInstance.data.datasets[0].data.push(value);
|
chartInstance.data.datasets[0].data.push(value);
|
||||||
if (chartInstance.data.datasets[0].data.length > 100) {
|
if (chartInstance.data.datasets[0].data.length > 100) {
|
||||||
|
@ -67,6 +67,8 @@ const color =
|
||||||
'?' as never;
|
'?' as never;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (chartEl.value == null) return;
|
||||||
|
|
||||||
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
|
||||||
|
|
||||||
chartInstance = new Chart(chartEl.value, {
|
chartInstance = new Chart(chartEl.value, {
|
||||||
|
|
|
@ -38,7 +38,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { markRaw, onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
|
import { markRaw, onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XChart from './overview.queue.chart.vue';
|
import XChart from './overview.queue.chart.vue';
|
||||||
import type { ApQueueDomain } from '@/pages/admin/queue.vue';
|
import type { ApQueueDomain } from '@/pages/admin/federation-job-queue.vue';
|
||||||
import number from '@/filters/number.js';
|
import number from '@/filters/number.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import { genId } from '@/utility/id.js';
|
import { genId } from '@/utility/id.js';
|
||||||
|
@ -64,10 +64,10 @@ function onStats(stats: Misskey.entities.QueueStats) {
|
||||||
delayed.value = stats[props.domain].delayed;
|
delayed.value = stats[props.domain].delayed;
|
||||||
waiting.value = stats[props.domain].waiting;
|
waiting.value = stats[props.domain].waiting;
|
||||||
|
|
||||||
chartProcess.value.pushData(stats[props.domain].activeSincePrevTick);
|
chartProcess.value?.pushData(stats[props.domain].activeSincePrevTick);
|
||||||
chartActive.value.pushData(stats[props.domain].active);
|
chartActive.value?.pushData(stats[props.domain].active);
|
||||||
chartDelayed.value.pushData(stats[props.domain].delayed);
|
chartDelayed.value?.pushData(stats[props.domain].delayed);
|
||||||
chartWaiting.value.pushData(stats[props.domain].waiting);
|
chartWaiting.value?.pushData(stats[props.domain].waiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) {
|
function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) {
|
||||||
|
@ -83,10 +83,10 @@ function onStatsLog(statsLog: Misskey.entities.QueueStatsLog) {
|
||||||
dataWaiting.push(stats[props.domain].waiting);
|
dataWaiting.push(stats[props.domain].waiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
chartProcess.value.setData(dataProcess);
|
chartProcess.value?.setData(dataProcess);
|
||||||
chartActive.value.setData(dataActive);
|
chartActive.value?.setData(dataActive);
|
||||||
chartDelayed.value.setData(dataDelayed);
|
chartDelayed.value?.setData(dataDelayed);
|
||||||
chartWaiting.value.setData(dataWaiting);
|
chartWaiting.value?.setData(dataWaiting);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -7,13 +7,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div>
|
<div>
|
||||||
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" mode="out-in">
|
<Transition :name="prefer.s.animation ? '_transition_zoom' : ''" mode="out-in">
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
<div v-else :class="$style.root">
|
<div v-else-if="stats != null" :class="$style.root">
|
||||||
<div class="item _panel users">
|
<div class="item _panel users">
|
||||||
<div class="icon"><i class="ti ti-users"></i></div>
|
<div class="icon"><i class="ti ti-users"></i></div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="value">
|
<div class="value">
|
||||||
<MkNumber :value="stats.originalUsersCount" style="margin-right: 0.5em;"/>
|
<MkNumber :value="stats.originalUsersCount" style="margin-right: 0.5em;"/>
|
||||||
<MkNumberDiff v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="usersComparedToThePrevDay"></MkNumberDiff>
|
<MkNumberDiff v-if="usersComparedToThePrevDay != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="usersComparedToThePrevDay"></MkNumberDiff>
|
||||||
</div>
|
</div>
|
||||||
<div class="label">Users</div>
|
<div class="label">Users</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="value">
|
<div class="value">
|
||||||
<MkNumber :value="stats.originalNotesCount" style="margin-right: 0.5em;"/>
|
<MkNumber :value="stats.originalNotesCount" style="margin-right: 0.5em;"/>
|
||||||
<MkNumberDiff v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="notesComparedToThePrevDay"></MkNumberDiff>
|
<MkNumberDiff v-if="notesComparedToThePrevDay != null" v-tooltip="i18n.ts.dayOverDayChanges" class="diff" :value="notesComparedToThePrevDay"></MkNumberDiff>
|
||||||
</div>
|
</div>
|
||||||
<div class="label">Notes</div>
|
<div class="label">Notes</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,6 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<MkError v-else/>
|
||||||
</Transition>
|
</Transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -71,8 +72,8 @@ import { customEmojis } from '@/custom-emojis.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
const stats = ref<Misskey.entities.StatsResponse | null>(null);
|
||||||
const usersComparedToThePrevDay = ref<number>();
|
const usersComparedToThePrevDay = ref<number | null>(null);
|
||||||
const notesComparedToThePrevDay = ref<number>();
|
const notesComparedToThePrevDay = ref<number | null>(null);
|
||||||
const onlineUsersCount = ref(0);
|
const onlineUsersCount = ref(0);
|
||||||
const fetching = ref(true);
|
const fetching = ref(true);
|
||||||
|
|
||||||
|
@ -85,11 +86,11 @@ onMounted(async () => {
|
||||||
onlineUsersCount.value = _onlineUsersCount;
|
onlineUsersCount.value = _onlineUsersCount;
|
||||||
|
|
||||||
misskeyApiGet('charts/users', { limit: 2, span: 'day' }).then(chart => {
|
misskeyApiGet('charts/users', { limit: 2, span: 'day' }).then(chart => {
|
||||||
usersComparedToThePrevDay.value = stats.value.originalUsersCount - chart.local.total[1];
|
usersComparedToThePrevDay.value = _stats.originalUsersCount - chart.local.total[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
misskeyApiGet('charts/notes', { limit: 2, span: 'day' }).then(chart => {
|
misskeyApiGet('charts/notes', { limit: 2, span: 'day' }).then(chart => {
|
||||||
notesComparedToThePrevDay.value = stats.value.originalNotesCount - chart.local.total[1];
|
notesComparedToThePrevDay.value = _stats.originalNotesCount - chart.local.total[1];
|
||||||
});
|
});
|
||||||
|
|
||||||
fetching.value = false;
|
fetching.value = false;
|
||||||
|
|
|
@ -95,7 +95,7 @@ const federationPubActiveDiff = ref<number | null>(null);
|
||||||
const federationSubActive = ref<number | null>(null);
|
const federationSubActive = ref<number | null>(null);
|
||||||
const federationSubActiveDiff = ref<number | null>(null);
|
const federationSubActiveDiff = ref<number | null>(null);
|
||||||
const newUsers = ref<Misskey.entities.UserDetailed[] | null>(null);
|
const newUsers = ref<Misskey.entities.UserDetailed[] | null>(null);
|
||||||
const activeInstances = shallowRef<Misskey.entities.FederationInstance | null>(null);
|
const activeInstances = shallowRef<Misskey.entities.FederationInstancesResponse | null>(null);
|
||||||
const queueStatsConnection = markRaw(useStream().useChannel('queueStats'));
|
const queueStatsConnection = markRaw(useStream().useChannel('queueStats'));
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const filesPagination = {
|
const filesPagination = {
|
||||||
|
|
|
@ -830,7 +830,6 @@ import { watch, ref, computed } from 'vue';
|
||||||
import { throttle } from 'throttle-debounce';
|
import { throttle } from 'throttle-debounce';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import RolesEditorFormula from './RolesEditorFormula.vue';
|
import RolesEditorFormula from './RolesEditorFormula.vue';
|
||||||
import type { GetMkSelectValueTypesFromDef, MkSelectItem } from '@/components/MkSelect.vue';
|
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkColorInput from '@/components/MkColorInput.vue';
|
import MkColorInput from '@/components/MkColorInput.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
|
|
@ -71,7 +71,7 @@ import { Paginator } from '@/utility/paginator.js';
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
id?: string;
|
id: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const usersPaginator = markRaw(new Paginator('admin/roles/users', {
|
const usersPaginator = markRaw(new Paginator('admin/roles/users', {
|
||||||
|
|
|
@ -346,6 +346,7 @@ import { definePage } from '@/page.js';
|
||||||
import { instance, fetchInstance } from '@/instance.js';
|
import { instance, fetchInstance } from '@/instance.js';
|
||||||
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
import MkFoldableSection from '@/components/MkFoldableSection.vue';
|
||||||
import { useRouter } from '@/router.js';
|
import { useRouter } from '@/router.js';
|
||||||
|
import { deepClone } from '@/utility/clone.js';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -353,10 +354,7 @@ const baseRoleQ = ref('');
|
||||||
|
|
||||||
const roles = await misskeyApi('admin/roles/list');
|
const roles = await misskeyApi('admin/roles/list');
|
||||||
|
|
||||||
const policies = reactive<Record<typeof Misskey.rolePolicies[number], any>>({});
|
const policies = reactive(deepClone(instance.policies));
|
||||||
for (const ROLE_POLICY of Misskey.rolePolicies) {
|
|
||||||
policies[ROLE_POLICY] = instance.policies[ROLE_POLICY];
|
|
||||||
}
|
|
||||||
|
|
||||||
const avatarDecorationLimit = computed({
|
const avatarDecorationLimit = computed({
|
||||||
get: () => Math.min(16, Math.max(0, policies.avatarDecorationLimit)),
|
get: () => Math.min(16, Math.max(0, policies.avatarDecorationLimit)),
|
||||||
|
@ -376,6 +374,7 @@ function matchQuery(keywords: string[]): boolean {
|
||||||
|
|
||||||
async function updateBaseRole() {
|
async function updateBaseRole() {
|
||||||
await os.apiWithDialog('admin/roles/update-default-policies', {
|
await os.apiWithDialog('admin/roles/update-default-policies', {
|
||||||
|
//@ts-expect-error misskey-js側の型定義が不十分
|
||||||
policies,
|
policies,
|
||||||
});
|
});
|
||||||
fetchInstance(true);
|
fetchInstance(true);
|
||||||
|
|
|
@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="title">{{ post.title }}</div>
|
<div class="title">{{ post.title }}</div>
|
||||||
<div class="description"><Mfm :text="post.description"/></div>
|
<div class="description"><Mfm v-if="post.description != null" :text="post.description"/></div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<i class="ti ti-clock"></i> <MkTime :time="post.createdAt" mode="detail"/>
|
<i class="ti ti-clock"></i> <MkTime :time="post.createdAt" mode="detail"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -93,7 +93,7 @@ const error = ref<any>(null);
|
||||||
const otherPostsPaginator = markRaw(new Paginator('users/gallery/posts', {
|
const otherPostsPaginator = markRaw(new Paginator('users/gallery/posts', {
|
||||||
limit: 6,
|
limit: 6,
|
||||||
computedParams: computed(() => ({
|
computedParams: computed(() => ({
|
||||||
userId: post.value.user.id,
|
userId: post.value!.user.id,
|
||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -109,33 +109,38 @@ function fetchPost() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyLink() {
|
function copyLink() {
|
||||||
|
if (!post.value) return;
|
||||||
copyToClipboard(`${url}/gallery/${post.value.id}`);
|
copyToClipboard(`${url}/gallery/${post.value.id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function share() {
|
function share() {
|
||||||
|
if (!post.value) return;
|
||||||
navigator.share({
|
navigator.share({
|
||||||
title: post.value.title,
|
title: post.value.title,
|
||||||
text: post.value.description,
|
text: post.value.description ?? undefined,
|
||||||
url: `${url}/gallery/${post.value.id}`,
|
url: `${url}/gallery/${post.value.id}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function shareWithNote() {
|
function shareWithNote() {
|
||||||
|
if (!post.value) return;
|
||||||
os.post({
|
os.post({
|
||||||
initialText: `${post.value.title} ${url}/gallery/${post.value.id}`,
|
initialText: `${post.value.title} ${url}/gallery/${post.value.id}`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function like() {
|
function like() {
|
||||||
|
if (!post.value) return;
|
||||||
os.apiWithDialog('gallery/posts/like', {
|
os.apiWithDialog('gallery/posts/like', {
|
||||||
postId: props.postId,
|
postId: props.postId,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
post.value.isLiked = true;
|
post.value!.isLiked = true;
|
||||||
post.value.likedCount++;
|
post.value!.likedCount++;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unlike() {
|
async function unlike() {
|
||||||
|
if (!post.value) return;
|
||||||
const confirm = await os.confirm({
|
const confirm = await os.confirm({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
text: i18n.ts.unlikeConfirm,
|
text: i18n.ts.unlikeConfirm,
|
||||||
|
@ -144,8 +149,8 @@ async function unlike() {
|
||||||
os.apiWithDialog('gallery/posts/unlike', {
|
os.apiWithDialog('gallery/posts/unlike', {
|
||||||
postId: props.postId,
|
postId: props.postId,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
post.value.isLiked = false;
|
post.value!.isLiked = false;
|
||||||
post.value.likedCount--;
|
post.value!.likedCount--;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MkButton v-if="list.isLiked" v-tooltip="i18n.ts.unlike" inline :class="$style.button" asLike primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="list.likedCount > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
<MkButton v-if="list.isLiked" v-tooltip="i18n.ts.unlike" inline :class="$style.button" asLike primary @click="unlike()"><i class="ti ti-heart-off"></i><span v-if="list.likedCount != null && list.likedCount > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
||||||
<MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
<MkButton v-if="!list.isLiked" v-tooltip="i18n.ts.like" inline :class="$style.button" asLike @click="like()"><i class="ti ti-heart"></i><span v-if="1 > 0" class="count">{{ list.likedCount }}</span></MkButton>
|
||||||
<MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton>
|
<MkButton inline @click="create()"><i class="ti ti-download" :class="$style.import"></i>{{ i18n.ts.import }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,7 +41,7 @@ const props = defineProps<{
|
||||||
listId: string;
|
listId: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const list = ref<Misskey.entities.UserList | null>(null);
|
const list = ref<Misskey.entities.UsersListsShowResponse | null>(null);
|
||||||
const error = ref<unknown | null>(null);
|
const error = ref<unknown | null>(null);
|
||||||
const users = ref<Misskey.entities.UserDetailed[]>([]);
|
const users = ref<Misskey.entities.UserDetailed[]>([]);
|
||||||
|
|
||||||
|
@ -51,8 +51,9 @@ function fetchList(): void {
|
||||||
forPublic: true,
|
forPublic: true,
|
||||||
}).then(_list => {
|
}).then(_list => {
|
||||||
list.value = _list;
|
list.value = _list;
|
||||||
|
if (_list.userIds == null || _list.userIds.length === 0) return;
|
||||||
misskeyApi('users/show', {
|
misskeyApi('users/show', {
|
||||||
userIds: list.value.userIds,
|
userIds: _list.userIds,
|
||||||
}).then(_users => {
|
}).then(_users => {
|
||||||
users.value = _users;
|
users.value = _users;
|
||||||
});
|
});
|
||||||
|
@ -68,7 +69,7 @@ function like() {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (list.value == null) return;
|
if (list.value == null) return;
|
||||||
list.value.isLiked = true;
|
list.value.isLiked = true;
|
||||||
list.value.likedCount++;
|
list.value.likedCount = (list.value.likedCount != null ? list.value.likedCount + 1 : 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ function unlike() {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (list.value == null) return;
|
if (list.value == null) return;
|
||||||
list.value.isLiked = false;
|
list.value.isLiked = false;
|
||||||
list.value.likedCount--;
|
list.value.likedCount = (list.value.likedCount != null ? Math.max(0, list.value.likedCount - 1) : 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ async function create() {
|
||||||
const { canceled, result: name } = await os.inputText({
|
const { canceled, result: name } = await os.inputText({
|
||||||
title: i18n.ts.enterListName,
|
title: i18n.ts.enterListName,
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled || name == null) return;
|
||||||
await os.apiWithDialog('users/lists/create-from-public', { name: name, listId: list.value.id });
|
await os.apiWithDialog('users/lists/create-from-public', { name: name, listId: list.value.id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'update:modelValue', value: Misskey.entities.PageBlock & { type: 'note' }): void;
|
(ev: 'update:modelValue', value: Misskey.entities.PageBlock & { type: 'note' }): void;
|
||||||
|
(ev: 'remove'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const id = ref(props.modelValue.note);
|
const id = ref(props.modelValue.note);
|
||||||
|
|
|
@ -71,7 +71,7 @@ async function add() {
|
||||||
title: i18n.ts._pages.chooseBlock,
|
title: i18n.ts._pages.chooseBlock,
|
||||||
items: getPageBlockList(),
|
items: getPageBlockList(),
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled || type == null) return;
|
||||||
|
|
||||||
const id = genId();
|
const id = genId();
|
||||||
children.value.push({ id, type });
|
children.value.push({ id, type });
|
||||||
|
|
|
@ -27,6 +27,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'update:modelValue', value: Misskey.entities.PageBlock & { type: 'text' }): void;
|
(ev: 'update:modelValue', value: Misskey.entities.PageBlock & { type: 'text' }): void;
|
||||||
|
(ev: 'remove'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let autocomplete: Autocomplete;
|
let autocomplete: Autocomplete;
|
||||||
|
@ -42,6 +43,7 @@ watch(text, () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (inputEl.value == null) return;
|
||||||
autocomplete = new Autocomplete(inputEl.value, text);
|
autocomplete = new Autocomplete(inputEl.value, text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
|
<PageWithHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs">
|
||||||
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
<div class="_spacer" style="--MI_SPACER-w: 700px;">
|
||||||
<div class="jqqmcavi">
|
<div class="jqqmcavi">
|
||||||
<MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="ti ti-external-link"></i> {{ i18n.ts._pages.viewPage }}</MkButton>
|
<MkButton v-if="pageId && author != null" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="ti ti-external-link"></i> {{ i18n.ts._pages.viewPage }}</MkButton>
|
||||||
<MkButton v-if="!readonly" inline primary class="button" @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
<MkButton v-if="!readonly" inline primary class="button" @click="save"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
||||||
<MkButton v-if="pageId" inline class="button" @click="duplicate"><i class="ti ti-copy"></i> {{ i18n.ts.duplicate }}</MkButton>
|
<MkButton v-if="pageId" inline class="button" @click="duplicate"><i class="ti ti-copy"></i> {{ i18n.ts.duplicate }}</MkButton>
|
||||||
<MkButton v-if="pageId && !readonly" inline class="button" danger @click="del"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
|
<MkButton v-if="pageId && !readonly" inline class="button" danger @click="del"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
|
||||||
|
@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInput v-model="name">
|
<MkInput v-model="name">
|
||||||
<template #prefix>{{ url }}/@{{ author.username }}/pages/</template>
|
<template #prefix>{{ url }}/@{{ author?.username ?? '???' }}/pages/</template>
|
||||||
<template #label>{{ i18n.ts._pages.url }}</template>
|
<template #label>{{ i18n.ts._pages.url }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const tab = ref('settings');
|
const tab = ref('settings');
|
||||||
const author = ref($i);
|
const author = ref<Misskey.entities.User | null>($i);
|
||||||
const readonly = ref(false);
|
const readonly = ref(false);
|
||||||
const page = ref<Misskey.entities.Page | null>(null);
|
const page = ref<Misskey.entities.Page | null>(null);
|
||||||
const pageId = ref<string | null>(null);
|
const pageId = ref<string | null>(null);
|
||||||
|
@ -202,11 +202,10 @@ async function duplicate() {
|
||||||
|
|
||||||
async function add() {
|
async function add() {
|
||||||
const { canceled, result: type } = await os.select({
|
const { canceled, result: type } = await os.select({
|
||||||
type: null,
|
|
||||||
title: i18n.ts._pages.chooseBlock,
|
title: i18n.ts._pages.chooseBlock,
|
||||||
items: getPageBlockList(),
|
items: getPageBlockList(),
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled || type == null) return;
|
||||||
|
|
||||||
const id = genId();
|
const id = genId();
|
||||||
content.value.push({ id, type });
|
content.value.push({ id, type });
|
||||||
|
|
|
@ -164,7 +164,7 @@ const $i = ensureSignin();
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
game: Misskey.entities.ReversiGameDetailed;
|
game: Misskey.entities.ReversiGameDetailed;
|
||||||
connection?: Misskey.ChannelConnection<Misskey.Channels['reversiGame']> | null;
|
connection?: Misskey.IChannelConnection<Misskey.Channels['reversiGame']> | null;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const showBoardLabels = ref<boolean>(false);
|
const showBoardLabels = ref<boolean>(false);
|
||||||
|
|
|
@ -132,7 +132,7 @@ const mapCategories = Array.from(new Set(Object.values(Reversi.maps).map(x => x.
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
game: Misskey.entities.ReversiGameDetailed;
|
game: Misskey.entities.ReversiGameDetailed;
|
||||||
connection: Misskey.ChannelConnection<Misskey.Channels['reversiGame']>;
|
connection: Misskey.IChannelConnection<Misskey.Channels['reversiGame']>;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const shareWhenStart = defineModel<boolean>('shareWhenStart', { default: false });
|
const shareWhenStart = defineModel<boolean>('shareWhenStart', { default: false });
|
||||||
|
|
|
@ -33,7 +33,7 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const game = shallowRef<Misskey.entities.ReversiGameDetailed | null>(null);
|
const game = shallowRef<Misskey.entities.ReversiGameDetailed | null>(null);
|
||||||
const connection = shallowRef<Misskey.ChannelConnection | null>(null);
|
const connection = shallowRef<Misskey.IChannelConnection<Misskey.Channels['reversiGame']> | null>(null);
|
||||||
const shareWhenStart = ref(false);
|
const shareWhenStart = ref(false);
|
||||||
|
|
||||||
watch(() => props.gameId, () => {
|
watch(() => props.gameId, () => {
|
||||||
|
|
|
@ -196,6 +196,7 @@ async function addSecurityKey() {
|
||||||
if (auth.canceled) return;
|
if (auth.canceled) return;
|
||||||
|
|
||||||
const registrationOptions = parseCreationOptionsFromJSON({
|
const registrationOptions = parseCreationOptionsFromJSON({
|
||||||
|
// @ts-expect-error misskey-js側に型がない
|
||||||
publicKey: await os.apiWithDialog('i/2fa/register-key', {
|
publicKey: await os.apiWithDialog('i/2fa/register-key', {
|
||||||
password: auth.result.password,
|
password: auth.result.password,
|
||||||
token: auth.result.token,
|
token: auth.result.token,
|
||||||
|
@ -226,6 +227,7 @@ async function addSecurityKey() {
|
||||||
password: auth.result.password,
|
password: auth.result.password,
|
||||||
token: auth.result.token,
|
token: auth.result.token,
|
||||||
name: name.result,
|
name: name.result,
|
||||||
|
// @ts-expect-error misskey-js側に型がない
|
||||||
credential: credential.toJSON(),
|
credential: credential.toJSON(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #label><SearchLabel>{{ i18n.ts._accountSettings.makeNotesFollowersOnlyBefore }}</SearchLabel></template>
|
<template #label><SearchLabel>{{ i18n.ts._accountSettings.makeNotesFollowersOnlyBefore }}</SearchLabel></template>
|
||||||
|
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<MkSelect :modelValue="makeNotesFollowersOnlyBefore_type" @update:modelValue="makeNotesFollowersOnlyBefore = $event === 'relative' ? -604800 : $event === 'absolute' ? Math.floor(Date.now() / 1000) : null">
|
<MkSelect v-model="makeNotesFollowersOnlyBefore_type">
|
||||||
<option :value="null">{{ i18n.ts.none }}</option>
|
<option :value="null">{{ i18n.ts.none }}</option>
|
||||||
<option value="relative">{{ i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod }}</option>
|
<option value="relative">{{ i18n.ts._accountSettings.notesHavePassedSpecifiedPeriod }}</option>
|
||||||
<option value="absolute">{{ i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime }}</option>
|
<option value="absolute">{{ i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime }}</option>
|
||||||
|
@ -140,7 +140,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInput
|
<MkInput
|
||||||
v-if="makeNotesFollowersOnlyBefore_type === 'absolute'"
|
v-if="makeNotesFollowersOnlyBefore_type === 'absolute' && makeNotesFollowersOnlyBefore != null"
|
||||||
:modelValue="formatDateTimeString(new Date(makeNotesFollowersOnlyBefore * 1000), 'yyyy-MM-dd')"
|
:modelValue="formatDateTimeString(new Date(makeNotesFollowersOnlyBefore * 1000), 'yyyy-MM-dd')"
|
||||||
type="date"
|
type="date"
|
||||||
:manualSave="true"
|
:manualSave="true"
|
||||||
|
@ -161,6 +161,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<MkSelect
|
<MkSelect
|
||||||
|
v-model="makeNotesHiddenBefore_type"
|
||||||
:items="[{
|
:items="[{
|
||||||
value: null,
|
value: null,
|
||||||
label: i18n.ts.none
|
label: i18n.ts.none
|
||||||
|
@ -170,7 +171,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
}, {
|
}, {
|
||||||
value: 'absolute',
|
value: 'absolute',
|
||||||
label: i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime
|
label: i18n.ts._accountSettings.notesOlderThanSpecifiedDateAndTime
|
||||||
}] as const" :modelValue="makeNotesHiddenBefore_type" @update:modelValue="makeNotesHiddenBefore = $event === 'relative' ? -604800 : $event === 'absolute' ? Math.floor(Date.now() / 1000) : null"
|
}]"
|
||||||
>
|
>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
|
|
||||||
|
@ -189,7 +190,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInput
|
<MkInput
|
||||||
v-if="makeNotesHiddenBefore_type === 'absolute'"
|
v-if="makeNotesHiddenBefore_type === 'absolute' && makeNotesHiddenBefore != null"
|
||||||
:modelValue="formatDateTimeString(new Date(makeNotesHiddenBefore * 1000), 'yyyy-MM-dd')"
|
:modelValue="formatDateTimeString(new Date(makeNotesHiddenBefore * 1000), 'yyyy-MM-dd')"
|
||||||
type="date"
|
type="date"
|
||||||
:manualSave="true"
|
:manualSave="true"
|
||||||
|
@ -217,7 +218,6 @@ import { ref, computed, watch } from 'vue';
|
||||||
import MkSwitch from '@/components/MkSwitch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
@ -247,14 +247,25 @@ const followingVisibility = ref($i.followingVisibility);
|
||||||
const followersVisibility = ref($i.followersVisibility);
|
const followersVisibility = ref($i.followersVisibility);
|
||||||
const chatScope = ref($i.chatScope);
|
const chatScope = ref($i.chatScope);
|
||||||
|
|
||||||
const makeNotesFollowersOnlyBefore_type = computed(() => {
|
const makeNotesFollowersOnlyBefore_type = computed({
|
||||||
if (makeNotesFollowersOnlyBefore.value == null) {
|
get: () => {
|
||||||
return null;
|
if (makeNotesFollowersOnlyBefore.value == null) {
|
||||||
} else if (makeNotesFollowersOnlyBefore.value >= 0) {
|
return null;
|
||||||
return 'absolute';
|
} else if (makeNotesFollowersOnlyBefore.value >= 0) {
|
||||||
} else {
|
return 'absolute';
|
||||||
return 'relative';
|
} else {
|
||||||
}
|
return 'relative';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
if (value === 'relative') {
|
||||||
|
makeNotesFollowersOnlyBefore.value = -604800;
|
||||||
|
} else if (value === 'absolute') {
|
||||||
|
makeNotesFollowersOnlyBefore.value = Math.floor(Date.now() / 1000);
|
||||||
|
} else {
|
||||||
|
makeNotesFollowersOnlyBefore.value = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeNotesFollowersOnlyBefore_presets = [
|
const makeNotesFollowersOnlyBefore_presets = [
|
||||||
|
@ -288,14 +299,25 @@ const makeNotesFollowersOnlyBefore_customMonths = computed({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeNotesHiddenBefore_type = computed(() => {
|
const makeNotesHiddenBefore_type = computed({
|
||||||
if (makeNotesHiddenBefore.value == null) {
|
get: () => {
|
||||||
return null;
|
if (makeNotesHiddenBefore.value == null) {
|
||||||
} else if (makeNotesHiddenBefore.value >= 0) {
|
return null;
|
||||||
return 'absolute';
|
} else if (makeNotesHiddenBefore.value >= 0) {
|
||||||
} else {
|
return 'absolute';
|
||||||
return 'relative';
|
} else {
|
||||||
}
|
return 'relative';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
if (value === 'relative') {
|
||||||
|
makeNotesHiddenBefore.value = -604800;
|
||||||
|
} else if (value === 'absolute') {
|
||||||
|
makeNotesHiddenBefore.value = Math.floor(Date.now() / 1000);
|
||||||
|
} else {
|
||||||
|
makeNotesHiddenBefore.value = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const makeNotesHiddenBefore_presets = [
|
const makeNotesHiddenBefore_presets = [
|
||||||
|
|
|
@ -41,25 +41,23 @@ import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api.js';
|
import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import { playMisskeySfxFile, soundsTypes, getSoundDuration } from '@/utility/sound.js';
|
import { playMisskeySfxFile, soundsTypes, getSoundDuration } from '@/utility/sound.js';
|
||||||
import { selectFile } from '@/utility/drive.js';
|
import { selectFile } from '@/utility/drive.js';
|
||||||
|
import type { SoundStore } from '@/preferences/def.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
type: SoundType;
|
def: SoundStore;
|
||||||
fileId?: string;
|
|
||||||
fileUrl?: string;
|
|
||||||
volume: number;
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'update', result: { type: SoundType; fileId?: string; fileUrl?: string; volume: number; }): void;
|
(ev: 'update', result: { type: SoundType; fileId?: string; fileUrl?: string; volume: number; }): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const type = ref<SoundType>(props.type);
|
const type = ref<SoundType>(props.def.type);
|
||||||
const fileId = ref(props.fileId);
|
const fileId = ref('fileId' in props.def ? props.def.fileId : undefined);
|
||||||
const fileUrl = ref(props.fileUrl);
|
const fileUrl = ref('fileUrl' in props.def ? props.def.fileUrl : undefined);
|
||||||
const fileName = ref<string>('');
|
const fileName = ref<string>('');
|
||||||
const driveFileError = ref(false);
|
const driveFileError = ref(false);
|
||||||
const hasChanged = ref(false);
|
const hasChanged = ref(false);
|
||||||
const volume = ref(props.volume);
|
const volume = ref(props.def.volume);
|
||||||
|
|
||||||
if (type.value === '_driveFile_' && fileId.value) {
|
if (type.value === '_driveFile_' && fileId.value) {
|
||||||
await misskeyApi('drive/files/show', {
|
await misskeyApi('drive/files/show', {
|
||||||
|
|
|
@ -42,7 +42,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template #suffix>{{ getSoundTypeName(sounds[type].type) }}</template>
|
<template #suffix>{{ getSoundTypeName(sounds[type].type) }}</template>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<template #default>
|
<template #default>
|
||||||
<XSound :type="sounds[type].type" :volume="sounds[type].volume" :fileId="sounds[type].fileId" :fileUrl="sounds[type].fileUrl" @update="(res) => updated(type, res)"/>
|
<XSound :def="sounds[type]" @update="(res) => updated(type, res)"/>
|
||||||
</template>
|
</template>
|
||||||
<template #fallback>
|
<template #fallback>
|
||||||
<MkLoading/>
|
<MkLoading/>
|
||||||
|
|
|
@ -112,8 +112,7 @@ async function init() {
|
||||||
...(visibleUserIds ? visibleUserIds.split(',').map(userId => ({ userId })) : []),
|
...(visibleUserIds ? visibleUserIds.split(',').map(userId => ({ userId })) : []),
|
||||||
...(visibleAccts ? visibleAccts.split(',').map(Misskey.acct.parse) : []),
|
...(visibleAccts ? visibleAccts.split(',').map(Misskey.acct.parse) : []),
|
||||||
]
|
]
|
||||||
// TypeScriptの指示通りに変換する
|
// @ts-expect-error payloadの引数側の型が正常に解決されない
|
||||||
.map(q => 'username' in q ? { username: q.username, host: q.host === null ? undefined : q.host } : q)
|
|
||||||
.map(q => misskeyApi('users/show', q)
|
.map(q => misskeyApi('users/show', q)
|
||||||
.then(user => {
|
.then(user => {
|
||||||
visibleUsers.value.push(user);
|
visibleUsers.value.push(user);
|
||||||
|
|
|
@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkPagination v-slot="{items}" :paginator="paginator" withControl>
|
<MkPagination v-slot="{items}" :paginator="paginator" withControl>
|
||||||
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/list/${ list.id }`">
|
<MkA v-for="list in items" :key="list.id" class="_panel" :class="$style.list" :to="`/list/${ list.id }`">
|
||||||
<div>{{ list.name }}</div>
|
<div>{{ list.name }}</div>
|
||||||
<MkAvatars :userIds="list.userIds"/>
|
<MkAvatars v-if="list.userIds != null" :userIds="list.userIds"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { ref } from 'vue';
|
||||||
import { compareVersions } from 'compare-versions';
|
import { compareVersions } from 'compare-versions';
|
||||||
import { isSafeMode } from '@@/js/config.js';
|
import { isSafeMode } from '@@/js/config.js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { Parser, Interpreter, values } from '@syuilo/aiscript';
|
import type { Parser, Interpreter, values, utils as utils_TypeReferenceOnly } from '@syuilo/aiscript';
|
||||||
import type { FormWithDefault } from '@/utility/form.js';
|
import type { FormWithDefault } from '@/utility/form.js';
|
||||||
import { genId } from '@/utility/id.js';
|
import { genId } from '@/utility/id.js';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
|
@ -82,22 +82,23 @@ export async function parsePluginMeta(code: string): Promise<AiScriptPluginMeta>
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata = meta.get(null);
|
const metadata = meta.get(null);
|
||||||
if (metadata == null) {
|
if (metadata == null || typeof metadata !== 'object' || Array.isArray(metadata)) {
|
||||||
throw new Error('Metadata not found');
|
throw new Error('Metadata not found or invalid');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, version, author, description, permissions, config } = metadata;
|
const { name, version, author, description, permissions, config } = metadata;
|
||||||
|
|
||||||
if (name == null || version == null || author == null) {
|
if (name == null || version == null || author == null) {
|
||||||
throw new Error('Required property not found');
|
throw new Error('Required property not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name,
|
name: name as string,
|
||||||
version,
|
version: version as string,
|
||||||
author,
|
author: author as string,
|
||||||
description,
|
description: description as string | undefined,
|
||||||
permissions,
|
permissions: permissions as string[] | undefined,
|
||||||
config,
|
config: config as Record<string, any> | undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ export async function authorizePlugin(plugin: Plugin) {
|
||||||
title: i18n.ts.tokenRequested,
|
title: i18n.ts.tokenRequested,
|
||||||
information: i18n.ts.pluginTokenRequestedDescription,
|
information: i18n.ts.pluginTokenRequestedDescription,
|
||||||
initialName: plugin.name,
|
initialName: plugin.name,
|
||||||
initialPermissions: plugin.permissions,
|
initialPermissions: plugin.permissions as typeof Misskey.permissions[number][],
|
||||||
}, {
|
}, {
|
||||||
done: async result => {
|
done: async result => {
|
||||||
const { name, permissions } = result;
|
const { name, permissions } = result;
|
||||||
|
@ -149,6 +150,7 @@ export async function installPlugin(code: string, meta?: AiScriptPluginMeta) {
|
||||||
|
|
||||||
const plugin = {
|
const plugin = {
|
||||||
...realMeta,
|
...realMeta,
|
||||||
|
config: realMeta.config ?? {},
|
||||||
installId,
|
installId,
|
||||||
active: true,
|
active: true,
|
||||||
configData: {},
|
configData: {},
|
||||||
|
@ -353,7 +355,9 @@ export function changePluginActive(plugin: Plugin, active: boolean) {
|
||||||
async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Promise<Record<string, values.Value>> {
|
async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Promise<Record<string, values.Value>> {
|
||||||
const id = opts.plugin.installId;
|
const id = opts.plugin.installId;
|
||||||
|
|
||||||
const { utils, values } = await import('@syuilo/aiscript');
|
const ais = await import('@syuilo/aiscript');
|
||||||
|
const values = ais.values;
|
||||||
|
const utils: typeof utils_TypeReferenceOnly = ais.utils;
|
||||||
const { createAiScriptEnv } = await import('@/aiscript/api.js');
|
const { createAiScriptEnv } = await import('@/aiscript/api.js');
|
||||||
|
|
||||||
const config = new Map<string, values.Value>();
|
const config = new Map<string, values.Value>();
|
||||||
|
@ -375,7 +379,7 @@ async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Pr
|
||||||
utils.assertFunction(handler);
|
utils.assertFunction(handler);
|
||||||
addPluginHandler(id, 'post_form_action', {
|
addPluginHandler(id, 'post_form_action', {
|
||||||
title: title.value,
|
title: title.value,
|
||||||
handler: withContext(ctx => (form, update) => {
|
handler: (form, update) => withContext(ctx => {
|
||||||
ctx.execFn(handler, [utils.jsToVal(form), values.FN_NATIVE(([key, value]) => {
|
ctx.execFn(handler, [utils.jsToVal(form), values.FN_NATIVE(([key, value]) => {
|
||||||
if (!key || !value) {
|
if (!key || !value) {
|
||||||
return;
|
return;
|
||||||
|
@ -391,7 +395,7 @@ async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Pr
|
||||||
utils.assertFunction(handler);
|
utils.assertFunction(handler);
|
||||||
addPluginHandler(id, 'user_action', {
|
addPluginHandler(id, 'user_action', {
|
||||||
title: title.value,
|
title: title.value,
|
||||||
handler: withContext(ctx => (user) => {
|
handler: (user) => withContext(ctx => {
|
||||||
ctx.execFn(handler, [utils.jsToVal(user)]);
|
ctx.execFn(handler, [utils.jsToVal(user)]);
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -402,7 +406,7 @@ async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Pr
|
||||||
utils.assertFunction(handler);
|
utils.assertFunction(handler);
|
||||||
addPluginHandler(id, 'note_action', {
|
addPluginHandler(id, 'note_action', {
|
||||||
title: title.value,
|
title: title.value,
|
||||||
handler: withContext(ctx => (note) => {
|
handler: (note) => withContext(ctx => {
|
||||||
ctx.execFn(handler, [utils.jsToVal(note)]);
|
ctx.execFn(handler, [utils.jsToVal(note)]);
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -411,8 +415,8 @@ async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Pr
|
||||||
'Plugin:register:note_view_interruptor': values.FN_NATIVE(([handler]) => {
|
'Plugin:register:note_view_interruptor': values.FN_NATIVE(([handler]) => {
|
||||||
utils.assertFunction(handler);
|
utils.assertFunction(handler);
|
||||||
addPluginHandler(id, 'note_view_interruptor', {
|
addPluginHandler(id, 'note_view_interruptor', {
|
||||||
handler: withContext(ctx => (note) => {
|
handler: (note) => withContext(ctx => {
|
||||||
return utils.valToJs(ctx.execFnSync(handler, [utils.jsToVal(note)]));
|
return utils.valToJs(ctx.execFnSync(handler, [utils.jsToVal(note)])) as Misskey.entities.Note | null;
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -420,8 +424,8 @@ async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Pr
|
||||||
'Plugin:register:note_post_interruptor': values.FN_NATIVE(([handler]) => {
|
'Plugin:register:note_post_interruptor': values.FN_NATIVE(([handler]) => {
|
||||||
utils.assertFunction(handler);
|
utils.assertFunction(handler);
|
||||||
addPluginHandler(id, 'note_post_interruptor', {
|
addPluginHandler(id, 'note_post_interruptor', {
|
||||||
handler: withContext(ctx => async (note) => {
|
handler: (note) => withContext(ctx => {
|
||||||
return utils.valToJs(await ctx.execFn(handler, [utils.jsToVal(note)]));
|
return utils.valToJs(ctx.execFnSync(handler, [utils.jsToVal(note)]));
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -429,8 +433,8 @@ async function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Pr
|
||||||
'Plugin:register:page_view_interruptor': values.FN_NATIVE(([handler]) => {
|
'Plugin:register:page_view_interruptor': values.FN_NATIVE(([handler]) => {
|
||||||
utils.assertFunction(handler);
|
utils.assertFunction(handler);
|
||||||
addPluginHandler(id, 'page_view_interruptor', {
|
addPluginHandler(id, 'page_view_interruptor', {
|
||||||
handler: withContext(ctx => async (page) => {
|
handler: (page) => withContext(ctx => {
|
||||||
return utils.valToJs(await ctx.execFn(handler, [utils.jsToVal(page)]));
|
return utils.valToJs(ctx.execFnSync(handler, [utils.jsToVal(page)])) as Misskey.entities.Page;
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -25,11 +25,14 @@ export function migrateOldSettings() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const plugins = ColdDeviceStorage.get('plugins');
|
const plugins = ColdDeviceStorage.get('plugins');
|
||||||
prefer.commit('plugins', plugins.map(p => ({
|
prefer.commit('plugins', plugins.map(p => {
|
||||||
...p,
|
const { id, ...rest } = p;
|
||||||
installId: (p as any).id,
|
return {
|
||||||
id: undefined,
|
...rest,
|
||||||
})));
|
config: rest.config ?? {},
|
||||||
|
installId: id,
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
prefer.commit('deck.profile', deckStore.s.profile);
|
prefer.commit('deck.profile', deckStore.s.profile);
|
||||||
misskeyApi('i/registry/keys', {
|
misskeyApi('i/registry/keys', {
|
||||||
|
@ -115,7 +118,13 @@ export function migrateOldSettings() {
|
||||||
prefer.commit('enableCondensedLine', store.s.enableCondensedLine);
|
prefer.commit('enableCondensedLine', store.s.enableCondensedLine);
|
||||||
prefer.commit('keepScreenOn', store.s.keepScreenOn);
|
prefer.commit('keepScreenOn', store.s.keepScreenOn);
|
||||||
prefer.commit('useGroupedNotifications', store.s.useGroupedNotifications);
|
prefer.commit('useGroupedNotifications', store.s.useGroupedNotifications);
|
||||||
prefer.commit('dataSaver', store.s.dataSaver);
|
prefer.commit('dataSaver', {
|
||||||
|
...prefer.s.dataSaver,
|
||||||
|
media: store.s.dataSaver.media,
|
||||||
|
avatar: store.s.dataSaver.avatar,
|
||||||
|
urlPreviewThumbnail: store.s.dataSaver.urlPreview,
|
||||||
|
code: store.s.dataSaver.code,
|
||||||
|
});
|
||||||
prefer.commit('enableSeasonalScreenEffect', store.s.enableSeasonalScreenEffect);
|
prefer.commit('enableSeasonalScreenEffect', store.s.enableSeasonalScreenEffect);
|
||||||
prefer.commit('enableHorizontalSwipe', store.s.enableHorizontalSwipe);
|
prefer.commit('enableHorizontalSwipe', store.s.enableHorizontalSwipe);
|
||||||
prefer.commit('useNativeUiForVideoAudioPlayer', store.s.useNativeUIForVideoAudioPlayer);
|
prefer.commit('useNativeUiForVideoAudioPlayer', store.s.useNativeUIForVideoAudioPlayer);
|
||||||
|
|
|
@ -41,6 +41,14 @@ export type StatusbarStore = {
|
||||||
props: Record<string, any>;
|
props: Record<string, any>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type DataSaverStore = {
|
||||||
|
media: boolean;
|
||||||
|
avatar: boolean;
|
||||||
|
urlPreviewThumbnail: boolean;
|
||||||
|
disableUrlPreview: boolean;
|
||||||
|
code: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
type OmitStrict<T, K extends keyof T> = T extends any ? Pick<T, Exclude<keyof T, K>> : never;
|
type OmitStrict<T, K extends keyof T> = T extends any ? Pick<T, Exclude<keyof T, K>> : never;
|
||||||
|
|
||||||
// NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる)
|
// NOTE: デフォルト値は他の設定の状態に依存してはならない(依存していた場合、ユーザーがその設定項目単体で「初期値にリセット」した場合不具合の原因になる)
|
||||||
|
@ -332,7 +340,7 @@ export const PREF_DEF = definePreferences({
|
||||||
urlPreviewThumbnail: false,
|
urlPreviewThumbnail: false,
|
||||||
disableUrlPreview: false,
|
disableUrlPreview: false,
|
||||||
code: false,
|
code: false,
|
||||||
} satisfies Record<string, boolean>,
|
} as DataSaverStore,
|
||||||
},
|
},
|
||||||
hemisphere: {
|
hemisphere: {
|
||||||
default: hemisphere as 'N' | 'S',
|
default: hemisphere as 'N' | 'S',
|
||||||
|
|
|
@ -381,7 +381,7 @@ export const store = markRaw(new Pizzax('base', {
|
||||||
avatar: false,
|
avatar: false,
|
||||||
urlPreview: false,
|
urlPreview: false,
|
||||||
code: false,
|
code: false,
|
||||||
} as Record<string, boolean>,
|
},
|
||||||
},
|
},
|
||||||
enableSeasonalScreenEffect: {
|
enableSeasonalScreenEffect: {
|
||||||
where: 'device',
|
where: 'device',
|
||||||
|
@ -483,7 +483,7 @@ export class ColdDeviceStorage {
|
||||||
lightTheme, // TODO: 消す(preferに移行済みのため)
|
lightTheme, // TODO: 消す(preferに移行済みのため)
|
||||||
darkTheme, // TODO: 消す(preferに移行済みのため)
|
darkTheme, // TODO: 消す(preferに移行済みのため)
|
||||||
syncDeviceDarkMode: true, // TODO: 消す(preferに移行済みのため)
|
syncDeviceDarkMode: true, // TODO: 消す(preferに移行済みのため)
|
||||||
plugins: [] as Plugin[], // TODO: 消す(preferに移行済みのため)
|
plugins: [] as (Omit<Plugin, 'installId'> & { id: string })[], // TODO: 消す(preferに移行済みのため)
|
||||||
};
|
};
|
||||||
|
|
||||||
public static watchers: Watcher[] = [];
|
public static watchers: Watcher[] = [];
|
||||||
|
|
|
@ -36,7 +36,7 @@ export async function getTheme(mode: 'light' | 'dark', getName = false): Promise
|
||||||
_res = deepClone(theme.codeHighlighter.overrides);
|
_res = deepClone(theme.codeHighlighter.overrides);
|
||||||
} else {
|
} else {
|
||||||
const base = await bundledThemesInfo.find(t => t.id === theme.codeHighlighter!.base)?.import() ?? darkPlus;
|
const base = await bundledThemesInfo.find(t => t.id === theme.codeHighlighter!.base)?.import() ?? darkPlus;
|
||||||
_res = deepMerge(theme.codeHighlighter.overrides ?? {}, 'default' in base ? base.default : base);
|
_res = deepMerge<ThemeRegistration>(theme.codeHighlighter.overrides ?? {}, 'default' in base ? base.default : base);
|
||||||
}
|
}
|
||||||
if (_res.name == null) {
|
if (_res.name == null) {
|
||||||
_res.name = theme.id;
|
_res.name = theme.id;
|
||||||
|
|
|
@ -130,11 +130,11 @@ type GetItemType<Item extends FormItem> =
|
||||||
: Item extends RadioFormItem
|
: Item extends RadioFormItem
|
||||||
? GetRadioItemType<Item>
|
? GetRadioItemType<Item>
|
||||||
: Item extends RangeFormItem
|
: Item extends RangeFormItem
|
||||||
? NonNullableIfRequired<InferDefault<RangeFormItem, number>, Item>
|
? NonNullableIfRequired<InferDefault<Item, number>, Item>
|
||||||
: Item extends EnumFormItem
|
: Item extends EnumFormItem
|
||||||
? GetEnumItemType<Item>
|
? GetEnumItemType<Item>
|
||||||
: Item extends ArrayFormItem
|
: Item extends ArrayFormItem
|
||||||
? NonNullableIfRequired<InferDefault<ArrayFormItem, unknown[]>, Item>
|
? NonNullableIfRequired<InferDefault<Item, unknown[]>, Item>
|
||||||
: Item extends ObjectFormItem
|
: Item extends ObjectFormItem
|
||||||
? NonNullableIfRequired<InferDefault<Item, Record<string, unknown>>, Item>
|
? NonNullableIfRequired<InferDefault<Item, Record<string, unknown>>, Item>
|
||||||
: Item extends DriveFileFormItem
|
: Item extends DriveFileFormItem
|
||||||
|
|
|
@ -289,7 +289,6 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: Router
|
||||||
caseSensitive: antenna.caseSensitive,
|
caseSensitive: antenna.caseSensitive,
|
||||||
withReplies: antenna.withReplies,
|
withReplies: antenna.withReplies,
|
||||||
withFile: antenna.withFile,
|
withFile: antenna.withFile,
|
||||||
notify: antenna.notify,
|
|
||||||
});
|
});
|
||||||
antennasCache.delete();
|
antennasCache.delete();
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,7 +35,7 @@ describe('MkUrlPreview', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = render(MkUrlPreview, {
|
const result = render(MkUrlPreview, {
|
||||||
props: { url: summary.url },
|
props: { url: summary.url! },
|
||||||
global: { directives, components },
|
global: { directives, components },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -818,6 +818,18 @@ export type Channels = {
|
||||||
};
|
};
|
||||||
receives: null;
|
receives: null;
|
||||||
};
|
};
|
||||||
|
reversi: {
|
||||||
|
params: null;
|
||||||
|
events: {
|
||||||
|
matched: (payload: {
|
||||||
|
game: ReversiGameDetailed;
|
||||||
|
}) => void;
|
||||||
|
invited: (payload: {
|
||||||
|
user: User;
|
||||||
|
}) => void;
|
||||||
|
};
|
||||||
|
receives: null;
|
||||||
|
};
|
||||||
reversiGame: {
|
reversiGame: {
|
||||||
params: {
|
params: {
|
||||||
gameId: string;
|
gameId: string;
|
||||||
|
@ -3838,8 +3850,8 @@ type VerifyEmailRequest = operations['verify-email']['requestBody']['content']['
|
||||||
//
|
//
|
||||||
// src/entities.ts:55:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
|
// src/entities.ts:55:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
|
||||||
// src/streaming.ts:57:3 - (ae-forgotten-export) The symbol "ReconnectingWebSocket" needs to be exported by the entry point index.d.ts
|
// src/streaming.ts:57:3 - (ae-forgotten-export) The symbol "ReconnectingWebSocket" needs to be exported by the entry point index.d.ts
|
||||||
// src/streaming.types.ts:218:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts
|
// src/streaming.types.ts:226:4 - (ae-forgotten-export) The symbol "ReversiUpdateKey" needs to be exported by the entry point index.d.ts
|
||||||
// src/streaming.types.ts:228:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" needs to be exported by the entry point index.d.ts
|
// src/streaming.types.ts:236:4 - (ae-forgotten-export) The symbol "ReversiUpdateSettings" needs to be exported by the entry point index.d.ts
|
||||||
|
|
||||||
// (No @packageDocumentation comment for this package)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
||||||
|
|
|
@ -6049,7 +6049,9 @@ export interface operations {
|
||||||
[name: string]: unknown;
|
[name: string]: unknown;
|
||||||
};
|
};
|
||||||
content: {
|
content: {
|
||||||
'application/json': components['schemas']['MeDetailed'];
|
'application/json': components['schemas']['MeDetailed'] & {
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Client error */
|
/** @description Client error */
|
||||||
|
@ -35333,7 +35335,10 @@ export interface operations {
|
||||||
[name: string]: unknown;
|
[name: string]: unknown;
|
||||||
};
|
};
|
||||||
content: {
|
content: {
|
||||||
'application/json': components['schemas']['UserList'];
|
'application/json': components['schemas']['UserList'] & {
|
||||||
|
likedCount?: number;
|
||||||
|
isLiked?: boolean;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Client error */
|
/** @description Client error */
|
||||||
|
|
|
@ -206,6 +206,14 @@ export type Channels = {
|
||||||
};
|
};
|
||||||
receives: null;
|
receives: null;
|
||||||
};
|
};
|
||||||
|
reversi: {
|
||||||
|
params: null;
|
||||||
|
events: {
|
||||||
|
matched: (payload: { game: ReversiGameDetailed }) => void;
|
||||||
|
invited: (payload: { user: User }) => void;
|
||||||
|
};
|
||||||
|
receives: null;
|
||||||
|
};
|
||||||
reversiGame: {
|
reversiGame: {
|
||||||
params: {
|
params: {
|
||||||
gameId: string;
|
gameId: string;
|
||||||
|
|
Loading…
Reference in New Issue