Merge tag '2023.9.0' into merge-upstream

This commit is contained in:
riku6460
2023-09-25 12:43:07 +09:00
1235 changed files with 19016 additions and 13835 deletions

View File

@@ -9,16 +9,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-show="loaded" :class="$style.root">
<img :src="serverErrorImageUrl" class="_ghost" :class="$style.img"/>
<div class="_gaps">
<p><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p>
<p v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</p>
<p v-else-if="serverIsDead">{{ i18n.ts.serverIsDead }}</p>
<div><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></div>
<div v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</div>
<div v-else-if="serverIsDead">{{ i18n.ts.serverIsDead }}</div>
<template v-else>
<p>{{ i18n.ts.newVersionOfClientAvailable }}</p>
<p>{{ i18n.ts.youShouldUpgradeClient }}</p>
<div>{{ i18n.ts.newVersionOfClientAvailable }}</div>
<div>{{ i18n.ts.youShouldUpgradeClient }}</div>
<MkButton style="margin: 8px auto;" @click="reload">{{ i18n.ts.reload }}</MkButton>
</template>
<p><MkA to="/docs/general/troubleshooting" class="_link">{{ i18n.ts.troubleshooting }}</MkA></p>
<p v-if="error" style="opacity: 0.7;">ERROR: {{ error }}</p>
<div><MkA to="/docs/general/troubleshooting" class="_link">{{ i18n.ts.troubleshooting }}</MkA></div>
<div v-if="error" style="opacity: 0.7;">ERROR: {{ error }}</div>
</div>
</div>
</Transition>
@@ -26,16 +26,16 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
import * as misskey from 'misskey-js';
import * as Misskey from 'misskey-js';
import MkButton from '@/components/MkButton.vue';
import { version } from '@/config';
import * as os from '@/os';
import { unisonReload } from '@/scripts/unison-reload';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { miLocalStorage } from '@/local-storage';
import { defaultStore } from '@/store';
import { serverErrorImageUrl } from '@/instance';
import { version } from '@/config.js';
import * as os from '@/os.js';
import { unisonReload } from '@/scripts/unison-reload.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { miLocalStorage } from '@/local-storage.js';
import { defaultStore } from '@/store.js';
import { serverErrorImageUrl } from '@/instance.js';
const props = withDefaults(defineProps<{
error?: Error;
@@ -44,7 +44,7 @@ const props = withDefaults(defineProps<{
let loaded = $ref(false);
let serverIsDead = $ref(false);
let meta = $ref<misskey.entities.LiteInstanceMetadata | null>(null);
let meta = $ref<Misskey.entities.LiteInstanceMetadata | null>(null);
os.api('meta', {
detail: false,

View File

@@ -111,18 +111,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { nextTick, onBeforeUnmount } from 'vue';
import { version } from '@/config';
import { version } from '@/config.js';
import FormLink from '@/components/form/link.vue';
import FormSection from '@/components/form/section.vue';
import MkButton from '@/components/MkButton.vue';
import MkLink from '@/components/MkLink.vue';
import { physics } from '@/scripts/physics';
import { i18n } from '@/i18n';
import { defaultStore } from '@/store';
import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata';
import { claimAchievement, claimedAchievements } from '@/scripts/achievements';
import { $i } from '@/account';
import { physics } from '@/scripts/physics.js';
import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js';
import { $i } from '@/account.js';
const patronsWithIcon = [{
name: 'カイヤン',
@@ -285,6 +285,8 @@ const patrons = [
'越貝鯛丸',
'Nick / pprmint.',
'kino3277',
'美少女JKぐーちゃん',
'てば',
];
let thereIsTreasure = $ref($i && !claimedAchievements.includes('foundTreasure'));

View File

@@ -42,9 +42,9 @@ import XEmoji from './emojis.emoji.vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { customEmojis, customEmojiCategories, getCustomEmojiTags } from '@/custom-emojis';
import { i18n } from '@/i18n';
import { $i } from '@/account';
import { customEmojis, customEmojiCategories, getCustomEmojiTags } from '@/custom-emojis.js';
import { i18n } from '@/i18n.js';
import { $i } from '@/account.js';
const customEmojiTags = getCustomEmojiTags();
let q = $ref('');

View File

@@ -53,10 +53,10 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed } from 'vue';
import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkPagination, { Paging } from '@/components/MkPagination.vue';
import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
import FormSplit from '@/components/form/split.vue';
import { i18n } from '@/i18n';
import { i18n } from '@/i18n.js';
let host = $ref('');
let state = $ref('federating');
@@ -64,6 +64,7 @@ let sort = $ref('+pubSub');
const pagination = {
endpoint: 'federation/instances' as const,
limit: 10,
displayLimit: 50,
offsetMode: true,
params: computed(() => ({
sort: sort,
@@ -77,7 +78,7 @@ const pagination = {
state === 'notResponding' ? { notResponding: true } :
{}),
})),
};
} as Paging;
function getStatus(instance) {
if (instance.isSuspended) return 'Suspended';

View File

@@ -101,7 +101,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed, watch } from 'vue';
import XEmojis from './about.emojis.vue';
import XFederation from './about.federation.vue';
import { version, host } from '@/config';
import { version, host } from '@/config.js';
import FormLink from '@/components/form/link.vue';
import FormSection from '@/components/form/section.vue';
import FormSuspense from '@/components/form/suspense.vue';
@@ -109,12 +109,12 @@ import FormSplit from '@/components/form/split.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkInstanceStats from '@/components/MkInstanceStats.vue';
import * as os from '@/os';
import number from '@/filters/number';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { claimAchievement } from '@/scripts/achievements';
import { instance } from '@/instance';
import * as os from '@/os.js';
import number from '@/filters/number.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { claimAchievement } from '@/scripts/achievements.js';
import { instance } from '@/instance.js';
const props = withDefaults(defineProps<{
initialTab?: string;

View File

@@ -15,10 +15,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onActivated, onDeactivated, onMounted, onUnmounted } from 'vue';
import MkAchievements from '@/components/MkAchievements.vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { $i } from '@/account';
import { claimAchievement } from '@/scripts/achievements';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { $i } from '@/account.js';
import { claimAchievement } from '@/scripts/achievements.js';
let timer: number | null;

View File

@@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #value><span class="_monospace"><MkTime :time="file.createdAt" mode="detail" style="display: block;"/></span></template>
</MkKeyValue>
</div>
<MkA v-if="file.user" class="user" :to="`/user-info/${file.user.id}`">
<MkA v-if="file.user" class="user" :to="`/admin/user/${file.user.id}`">
<MkUserCardMini :user="file.user"/>
</MkA>
<div>
@@ -76,11 +76,11 @@ import MkKeyValue from '@/components/MkKeyValue.vue';
import FormSection from '@/components/form/section.vue';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkInfo from '@/components/MkInfo.vue';
import bytes from '@/filters/bytes';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { iAmAdmin, iAmModerator } from '@/account';
import bytes from '@/filters/bytes.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { iAmAdmin, iAmModerator } from '@/account.js';
let tab = $ref('overview');
let file: any = $ref(null);

View File

@@ -25,12 +25,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInfo v-if="user.username.includes('.')">{{ i18n.ts.isSystemAccount }}</MkInfo>
<div v-if="user.url" class="_formLinksGrid">
<FormLink :to="userPage(user)">Profile</FormLink>
<FormLink :to="user.url" :external="true">Profile (remote)</FormLink>
</div>
<FormLink v-else :to="userPage(user)">Profile</FormLink>
<FormLink v-if="user.host" :to="`/instance-info/${user.host}`">{{ i18n.ts.instanceInfo }}</FormLink>
<div style="display: flex; flex-direction: column; gap: 1em;">
@@ -58,6 +52,11 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkKeyValue>
</div>
<MkTextarea v-model="moderationNote" manualSave>
<template #label>{{ i18n.ts.moderationNote }}</template>
</MkTextarea>
<!--
<FormSection>
<template #label>ActivityPub</template>
@@ -91,95 +90,85 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFolder>
</div>
</FormSection>
</div>
-->
<div v-else-if="tab === 'moderation'" class="_gaps_m">
<MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch>
<div>
<MkButton v-if="user.host == null && iAmModerator" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton>
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
</div>
<MkFolder>
<template #icon><i class="ti ti-license"></i></template>
<template #label>{{ i18n.ts._role.policies }}</template>
<FormSection>
<div class="_gaps">
<div v-for="policy in Object.keys(info.policies)" :key="policy">
{{ policy }} ... {{ info.policies[policy] }}
<MkSwitch v-model="suspended" @update:modelValue="toggleSuspend">{{ i18n.ts.suspend }}</MkSwitch>
<div>
<MkButton v-if="user.host == null" inline style="margin-right: 8px;" @click="resetPassword"><i class="ti ti-key"></i> {{ i18n.ts.resetPassword }}</MkButton>
</div>
</div>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-badges"></i></template>
<template #label>{{ i18n.ts.roles }}</template>
<div class="_gaps">
<MkButton v-if="user.host == null && iAmModerator" primary rounded @click="assignRole"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
<div v-for="role in info.roles" :key="role.id" :class="$style.roleItem">
<div :class="$style.roleItemMain">
<MkRolePreview :class="$style.role" :role="role" :forModeration="true"/>
<button class="_button" :class="$style.roleToggle" @click="toggleRoleItem(role)"><i class="ti ti-chevron-down"></i></button>
<button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="unassignRole(role, $event)"><i class="ti ti-x"></i></button>
<button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button>
<MkFolder>
<template #icon><i class="ti ti-license"></i></template>
<template #label>{{ i18n.ts._role.policies }}</template>
<div class="_gaps">
<div v-for="policy in Object.keys(info.policies)" :key="policy">
{{ policy }} ... {{ info.policies[policy] }}
</div>
</div>
<div v-if="expandedRoles.includes(role.id)" :class="$style.roleItemSub">
<div>Assigned: <MkTime :time="info.roleAssigns.find(a => a.roleId === role.id).createdAt" mode="detail"/></div>
<div v-if="info.roleAssigns.find(a => a.roleId === role.id).expiresAt">Period: {{ new Date(info.roleAssigns.find(a => a.roleId === role.id).expiresAt).toLocaleString() }}</div>
<div v-else>Period: {{ i18n.ts.indefinitely }}</div>
</div>
</div>
</div>
</MkFolder>
</MkFolder>
<MkFolder v-if="user.host == null && iAmModerator">
<template #icon><i class="ti ti-speakerphone"></i></template>
<template #label>{{ i18n.ts.announcements }}</template>
<div class="_gaps">
<MkButton primary rounded @click="createAnnouncement"><i class="ti ti-plus"></i> {{ i18n.ts.new }}</MkButton>
<MkPagination ref="announcementsPaginationEl" :pagination="announcementsPagination">
<template #default="{ items }">
<div class="_gaps_s">
<div v-for="announcement in items" :key="announcement.id" v-panel :class="$style.announcementItem" @click="editAnnouncement(announcement)">
<span style="margin-right: 0.5em;">
<i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
<i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i>
<i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
<i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
</span>
<span>{{ announcement.title }}</span>
<span v-if="announcement.reads > 0" style="margin-left: auto; opacity: 0.7;">{{ i18n.ts.messageRead }}</span>
</div>
<MkFolder>
<template #icon><i class="ti ti-password"></i></template>
<template #label>IP</template>
<MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo>
<MkInfo v-else>The date is the IP address was first acknowledged.</MkInfo>
<template v-if="iAmAdmin && ips">
<div v-for="record in ips" :key="record.ip" class="_monospace" :class="$style.ip" style="margin: 1em 0;">
<span class="date">{{ record.createdAt }}</span>
<span class="ip">{{ record.ip }}</span>
</div>
</template>
</MkPagination>
</div>
</MkFolder>
</MkFolder>
<MkFolder>
<template #icon><i class="ti ti-password"></i></template>
<template #label>IP</template>
<MkInfo v-if="!iAmAdmin" warn>{{ i18n.ts.requireAdminForView }}</MkInfo>
<MkInfo v-else>The date is the IP address was first acknowledged.</MkInfo>
<template v-if="iAmAdmin && ips">
<div v-for="record in ips" :key="record.ip" class="_monospace" :class="$style.ip" style="margin: 1em 0;">
<span class="date">{{ record.createdAt }}</span>
<span class="ip">{{ record.ip }}</span>
<MkButton v-if="$i.isAdmin" inline danger @click="deleteAccount">{{ i18n.ts.deleteAccount }}</MkButton>
</div>
</FormSection>
</div>
<div v-else-if="tab === 'roles'" class="_gaps">
<MkButton v-if="user.host == null" primary rounded @click="assignRole"><i class="ti ti-plus"></i> {{ i18n.ts.assign }}</MkButton>
<div v-for="role in info.roles" :key="role.id" :class="$style.roleItem">
<div :class="$style.roleItemMain">
<MkRolePreview :class="$style.role" :role="role" :forModeration="true"/>
<button class="_button" :class="$style.roleToggle" @click="toggleRoleItem(role)"><i class="ti ti-chevron-down"></i></button>
<button v-if="role.target === 'manual'" class="_button" :class="$style.roleUnassign" @click="unassignRole(role, $event)"><i class="ti ti-x"></i></button>
<button v-else class="_button" :class="$style.roleUnassign" disabled><i class="ti ti-ban"></i></button>
</div>
<div v-if="expandedRoles.includes(role.id)" :class="$style.roleItemSub">
<div>Assigned: <MkTime :time="info.roleAssigns.find(a => a.roleId === role.id).createdAt" mode="detail"/></div>
<div v-if="info.roleAssigns.find(a => a.roleId === role.id).expiresAt">Period: {{ new Date(info.roleAssigns.find(a => a.roleId === role.id).expiresAt).toLocaleString() }}</div>
<div v-else>Period: {{ i18n.ts.indefinitely }}</div>
</div>
</div>
</div>
<div v-else-if="tab === 'announcements'" class="_gaps">
<MkButton primary rounded @click="createAnnouncement"><i class="ti ti-plus"></i> {{ i18n.ts.new }}</MkButton>
<MkPagination ref="announcementsPaginationEl" :pagination="announcementsPagination">
<template #default="{ items }">
<div class="_gaps_s">
<div v-for="announcement in items" :key="announcement.id" v-panel :class="$style.announcementItem" @click="editAnnouncement(announcement)">
<span style="margin-right: 0.5em;">
<i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
<i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i>
<i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
<i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
</span>
<span>{{ announcement.title }}</span>
<span v-if="announcement.reads > 0" style="margin-left: auto; opacity: 0.7;">{{ i18n.ts.messageRead }}</span>
</div>
</div>
</template>
</MkFolder>
</MkPagination>
</div>
<MkFolder>
<template #icon><i class="ti ti-cloud"></i></template>
<template #label>{{ i18n.ts.files }}</template>
<MkFileListForAdmin :pagination="filesPagination" viewMode="grid"/>
</MkFolder>
<MkTextarea v-model="moderationNote" manualSave>
<template #label>Moderation note</template>
</MkTextarea>
<div v-else-if="tab === 'drive'" class="_gaps">
<MkFileListForAdmin :pagination="filesPagination" viewMode="grid"/>
</div>
<div v-else-if="tab === 'chart'" class="_gaps_m">
@@ -212,29 +201,28 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, defineAsyncComponent, ref, watch } from 'vue';
import * as misskey from 'misskey-js';
import * as os from '@/os';
import { url } from '@/config';
import { userPage, acct } from '@/filters/user';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { iAmAdmin, iAmModerator, $i } from '@/account';
import * as Misskey from 'misskey-js';
import MkChart from '@/components/MkChart.vue';
import MkObjectView from '@/components/MkObjectView.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import FormLink from '@/components/form/link.vue';
import FormSection from '@/components/form/section.vue';
import FormSuspense from '@/components/form/suspense.vue';
import MkButton from '@/components/MkButton.vue';
import MkChart from '@/components/MkChart.vue';
import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkObjectView from '@/components/MkObjectView.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkRolePreview from '@/components/MkRolePreview.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import { updateColumn } from '@/ui/deck/deck-store';
import FormSuspense from '@/components/form/suspense.vue';
import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
import MkInfo from '@/components/MkInfo.vue';
import * as os from '@/os.js';
import { url } from '@/config.js';
import { userPage, acct } from '@/filters/user.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
import { iAmAdmin, iAmModerator, $i } from '@/account.js';
import MkRolePreview from '@/components/MkRolePreview.vue';
import MkPagination, { Paging } from '@/components/MkPagination.vue';
const props = withDefaults(defineProps<{
userId: string;
@@ -245,7 +233,7 @@ const props = withDefaults(defineProps<{
let tab = $ref(props.initialTab);
let chartSrc = $ref('per-user-notes');
let user = $ref<null | misskey.entities.UserDetailed>();
let user = $ref<null | Misskey.entities.UserDetailed>();
let init = $ref<ReturnType<typeof createFetcher>>();
let info = $ref();
let ips = $ref(null);
@@ -274,35 +262,27 @@ const announcementsPagination = {
let expandedRoles = $ref([]);
function createFetcher() {
if (iAmModerator) {
return () => Promise.all([os.api('users/show', {
userId: props.userId,
}), os.api('admin/show-user', {
userId: props.userId,
}), iAmAdmin ? os.api('admin/get-user-ips', {
userId: props.userId,
}) : Promise.resolve(null)]).then(([_user, _info, _ips]) => {
user = _user;
info = _info;
ips = _ips;
moderator = info.isModerator;
silenced = info.isSilenced;
limited = info.isLimited;
suspended = info.isSuspended;
moderationNote = info.moderationNote;
return () => Promise.all([os.api('users/show', {
userId: props.userId,
}), os.api('admin/show-user', {
userId: props.userId,
}), iAmAdmin ? os.api('admin/get-user-ips', {
userId: props.userId,
}) : Promise.resolve(null)]).then(([_user, _info, _ips]) => {
user = _user;
info = _info;
ips = _ips;
moderator = info.isModerator;
silenced = info.isSilenced;
limited = info.isLimited;
suspended = info.isSuspended;
moderationNote = info.moderationNote;
watch($$(moderationNote), async () => {
await os.api('admin/update-user-note', { userId: user.id, text: moderationNote });
await refreshUser();
});
watch($$(moderationNote), async () => {
await os.api('admin/update-user-note', { userId: user.id, text: moderationNote });
await refreshUser();
});
} else {
return () => os.api('users/show', {
userId: props.userId,
}).then((res) => {
user = res;
});
}
});
}
function refreshUser() {
@@ -486,11 +466,19 @@ const headerTabs = $computed(() => [{
key: 'overview',
title: i18n.ts.overview,
icon: 'ti ti-info-circle',
}, iAmModerator ? {
key: 'moderation',
title: i18n.ts.moderation,
icon: 'ti ti-user-exclamation',
} : null, {
}, {
key: 'roles',
title: i18n.ts.roles,
icon: 'ti ti-badges',
}, {
key: 'announcements',
title: i18n.ts.announcements,
icon: 'ti ti-speakerphone',
}, {
key: 'drive',
title: i18n.ts.drive,
icon: 'ti ti-cloud',
}, {
key: 'chart',
title: i18n.ts.charts,
icon: 'ti ti-chart-line',
@@ -498,11 +486,11 @@ const headerTabs = $computed(() => [{
key: 'raw',
title: 'Raw',
icon: 'ti ti-code',
}].filter(x => x != null));
}]);
definePageMetadata(computed(() => ({
title: user ? acct(user) : i18n.ts.userInfo,
icon: 'ti ti-info-circle',
icon: 'ti ti-user-exclamation',
})));
</script>

View File

@@ -60,8 +60,8 @@ import { v4 as uuid } from 'uuid';
import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n';
import { deepClone } from '@/scripts/clone';
import { i18n } from '@/i18n.js';
import { deepClone } from '@/scripts/clone.js';
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));

View File

@@ -35,11 +35,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, onMounted, onUnmounted, ref, shallowRef, watch, nextTick } from 'vue';
import tinycolor from 'tinycolor2';
import { popupMenu } from '@/os';
import { scrollToTop } from '@/scripts/scroll';
import { popupMenu } from '@/os.js';
import { scrollToTop } from '@/scripts/scroll.js';
import MkButton from '@/components/MkButton.vue';
import { globalEvents } from '@/events';
import { injectPageMetadata } from '@/scripts/page-metadata';
import { injectPageMetadata } from '@/scripts/page-metadata.js';
type Tab = {
key?: string | null;

View File

@@ -87,9 +87,9 @@ import MkPagination from '@/components/MkPagination.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkAbuseReportResolver from '@/components/MkAbuseReportResolver.vue';
import XAbuseReport from '@/components/MkAbuseReport.vue';
import { i18n } from '@/i18n';
import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let reports = $shallowRef<InstanceType<typeof MkPagination>>();
let resolverPagingComponent = $ref<InstanceType<typeof MkPagination>>();

View File

@@ -76,9 +76,9 @@ import MkTextarea from '@/components/MkTextarea.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkFolder from '@/components/MkFolder.vue';
import FormSplit from '@/components/form/split.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let ads: any[] = $ref([]);

View File

@@ -72,7 +72,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-model="announcement.displayOrder" type="number">
<template #label>{{ i18n.ts.displayOrder }}</template>
</MkInput>
<p v-if="announcement.readCount">{{ i18n.t('nUsersRead', { n: announcement.readCount }) }}</p>
<p v-if="announcement.reads">{{ i18n.t('nUsersRead', { n: announcement.reads }) }}</p>
<MkUserCardMini v-if="announcement.userId" :user="announcement.user" @click="editUser(announcement)"></MkUserCardMini>
<MkButton v-else class="button" inline primary @click="editUser(announcement)">{{ i18n.ts.specifyUser }}</MkButton>
<div class="buttons _buttons">
@@ -82,7 +82,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</div>
</MkFolder>
<MkButton v-if="hasMore" :class="$style.more" :disabled="!hasMore" primary rounded @click="fetch()">{{ i18n.ts.loadMore }}</MkButton>
<MkButton v-if="hasMore" :class="$style.more" :disabled="!hasMore" primary rounded @click="fetch()">
<i class="ti ti-reload"></i>{{ i18n.ts.more }}
</MkButton>
</div>
</MkSpacer>
</MkStickyContainer>
@@ -92,15 +94,16 @@ SPDX-License-Identifier: AGPL-3.0-only
import { ref, watch } from 'vue';
import * as misskey from 'misskey-js';
import XHeader from './_header_.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkInput from '@/components/MkInput.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkInfo from '@/components/MkInfo.vue';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkFolder from '@/components/MkFolder.vue';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
const announceTitleEl = $shallowRef<HTMLInputElement | null>(null);
@@ -127,7 +130,7 @@ function insertEmoji(ev: MouseEvent): void {
os.openEmojiPicker((ev.currentTarget ?? ev.target) as HTMLElement, {}, announceTitleEl);
}
function add(): void {
function add() {
announcements.unshift({
_id: Math.random().toString(36),
id: null,
@@ -143,7 +146,7 @@ function add(): void {
});
}
function del(announcement): void {
function del(announcement) {
os.confirm({
type: 'warning',
text: i18n.t('deleteAreYouSure', { x: announcement.title }),
@@ -154,7 +157,7 @@ function del(announcement): void {
});
}
async function archive(announcement): Promise<void> {
async function archive(announcement) {
await os.apiWithDialog('admin/announcements/update', {
...announcement,
isActive: false,

View File

@@ -70,9 +70,9 @@ import MkInput from '@/components/MkInput.vue';
import MkButton from '@/components/MkButton.vue';
import FormSuspense from '@/components/form/suspense.vue';
import FormSlot from '@/components/form/slot.vue';
import * as os from '@/os';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
const MkCaptcha = defineAsyncComponent(() => import('@/components/MkCaptcha.vue'));

View File

@@ -12,7 +12,29 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_m">
<MkInput v-model="iconUrl">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.iconUrl }}</template>
<template #label>{{ i18n.ts._serverSettings.iconUrl }}</template>
</MkInput>
<MkInput v-model="app192IconUrl">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts._serverSettings.iconUrl }} (App/192px)</template>
<template #caption>
<div>{{ i18n.t('_serverSettings.appIconDescription', { host: instance.name ?? host }) }}</div>
<div>({{ i18n.ts._serverSettings.appIconUsageExample }})</div>
<div>{{ i18n.ts._serverSettings.appIconStyleRecommendation }}</div>
<div><strong>{{ i18n.t('_serverSettings.appIconResolutionMustBe', { resolution: '192x192px' }) }}</strong></div>
</template>
</MkInput>
<MkInput v-model="app512IconUrl">
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts._serverSettings.iconUrl }} (App/512px)</template>
<template #caption>
<div>{{ i18n.t('_serverSettings.appIconDescription', { host: instance.name ?? host }) }}</div>
<div>({{ i18n.ts._serverSettings.appIconUsageExample }})</div>
<div>{{ i18n.ts._serverSettings.appIconStyleRecommendation }}</div>
<div><strong>{{ i18n.t('_serverSettings.appIconResolutionMustBe', { resolution: '512x512px' }) }}</strong></div>
</template>
</MkInput>
<MkInput v-model="bannerUrl">
@@ -53,6 +75,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.instanceDefaultDarkTheme }}</template>
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
</MkTextarea>
<MkTextarea v-model="manifestJsonOverride">
<template #label>{{ i18n.ts._serverSettings.manifestJsonOverride }}</template>
</MkTextarea>
</div>
</FormSuspense>
</MkSpacer>
@@ -69,6 +95,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
import JSON5 from 'json5';
import XHeader from './_header_.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkInput from '@/components/MkInput.vue';
@@ -76,14 +103,17 @@ import MkTextarea from '@/components/MkTextarea.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';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { instance, fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
import MkColorInput from '@/components/MkColorInput.vue';
import { host } from '@/config.js';
let iconUrl: string | null = $ref(null);
let app192IconUrl: string | null = $ref(null);
let app512IconUrl: string | null = $ref(null);
let bannerUrl: string | null = $ref(null);
let backgroundImageUrl: string | null = $ref(null);
let themeColor: any = $ref(null);
@@ -92,10 +122,13 @@ let defaultDarkTheme: any = $ref(null);
let serverErrorImageUrl: string | null = $ref(null);
let infoImageUrl: string | null = $ref(null);
let notFoundImageUrl: string | null = $ref(null);
let manifestJsonOverride: string = $ref('{}');
async function init() {
const meta = await os.api('admin/meta');
iconUrl = meta.iconUrl;
app192IconUrl = meta.app192IconUrl;
app512IconUrl = meta.app512IconUrl;
bannerUrl = meta.bannerUrl;
backgroundImageUrl = meta.backgroundImageUrl;
themeColor = meta.themeColor;
@@ -104,11 +137,14 @@ async function init() {
serverErrorImageUrl = meta.serverErrorImageUrl;
infoImageUrl = meta.infoImageUrl;
notFoundImageUrl = meta.notFoundImageUrl;
manifestJsonOverride = meta.manifestJsonOverride === '' ? '{}' : JSON.stringify(JSON.parse(meta.manifestJsonOverride), null, '\t');
}
function save() {
os.apiWithDialog('admin/update-meta', {
iconUrl,
app192IconUrl,
app512IconUrl,
bannerUrl,
backgroundImageUrl,
themeColor: themeColor === '' ? null : themeColor,
@@ -117,6 +153,7 @@ function save() {
infoImageUrl,
notFoundImageUrl,
serverErrorImageUrl,
manifestJsonOverride: manifestJsonOverride === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride)),
}).then(() => {
fetchInstance();
});

View File

@@ -21,11 +21,11 @@ SPDX-License-Identifier: AGPL-3.0-only
import { } from 'vue';
import FormSuspense from '@/components/form/suspense.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import * as os from '@/os';
import bytes from '@/filters/bytes';
import number from '@/filters/number';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import bytes from '@/filters/bytes.js';
import number from '@/filters/number.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const databasePromiseFactory = () => os.api('admin/get-table-stats').then(res => Object.entries(res).sort((a, b) => b[1].size - a[1].size));

View File

@@ -72,10 +72,10 @@ import FormInfo from '@/components/MkInfo.vue';
import FormSuspense from '@/components/form/suspense.vue';
import FormSplit from '@/components/form/split.vue';
import FormSection from '@/components/form/section.vue';
import * as os from '@/os';
import { fetchInstance, instance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance, instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
let enableEmail: boolean = $ref(false);

View File

@@ -64,8 +64,8 @@ import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
import FormSplit from '@/components/form/split.vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let host = $ref('');
let state = $ref('federating');

View File

@@ -41,9 +41,9 @@ import XHeader from './_header_.vue';
import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let origin = $ref('local');
let type = $ref(null);

View File

@@ -29,14 +29,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onActivated, onMounted, onUnmounted, provide, watch } from 'vue';
import { i18n } from '@/i18n';
import { i18n } from '@/i18n.js';
import MkSuperMenu from '@/components/MkSuperMenu.vue';
import MkInfo from '@/components/MkInfo.vue';
import { instance } from '@/instance';
import * as os from '@/os';
import { lookupUser } from '@/scripts/lookup-user';
import { useRouter } from '@/router';
import { definePageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata';
import { instance } from '@/instance.js';
import * as os from '@/os.js';
import { lookupUser } from '@/scripts/lookup-user.js';
import { useRouter } from '@/router.js';
import { definePageMetadata, provideMetadataReceiver } from '@/scripts/page-metadata.js';
const isEmpty = (x: string | null) => x == null || x === '';
@@ -145,6 +145,11 @@ const menuDef = $computed(() => [{
text: i18n.ts.abuseReports,
to: '/admin/abuses',
active: currentPage?.route.name === 'abuses',
}, {
icon: 'ti ti-list-search',
text: i18n.ts.moderationLogs,
to: '/admin/modlog',
active: currentPage?.route.name === 'modlog',
}],
}, {
title: i18n.ts.settings,

View File

@@ -25,10 +25,10 @@ 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';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let blockedHosts: string = $ref('');

View File

@@ -57,8 +57,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, ref, shallowRef } from 'vue';
import XHeader from './_header_.vue';
import { i18n } from '@/i18n';
import * as os from '@/os';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import MkButton from '@/components/MkButton.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkSelect from '@/components/MkSelect.vue';
@@ -66,7 +66,7 @@ import MkInput from '@/components/MkInput.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkPagination, { Paging } from '@/components/MkPagination.vue';
import MkInviteCode from '@/components/MkInviteCode.vue';
import { definePageMetadata } from '@/scripts/page-metadata';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();

View File

@@ -57,10 +57,10 @@ import MkTextarea from '@/components/MkTextarea.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';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
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';

View File

@@ -0,0 +1,77 @@
<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkFolder>
<template #label>{{ i18n.ts._moderationLogTypes[log.type] }}</template>
<template #icon>
<MkAvatar :user="log.user" :class="$style.avatar"/>
</template>
<template #suffix>
<MkTime :time="log.createdAt" mode="detail"/>
</template>
<div :class="$style.root">
<div>{{ i18n.ts.moderator }}: {{ log.userId }}</div>
<template v-if="log.type === 'updateServerSettings'">
<div :class="$style.diff">
<CodeDiff :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
</div>
</template>
<template v-else-if="log.type === 'updateUserNote'">
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
<div :class="$style.diff">
<CodeDiff :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/>
</div>
</template>
<template v-else-if="log.type === 'suspend'">
<div>{{ i18n.ts.user }}: {{ log.info.targetId }}</div>
</template>
<template v-else-if="log.type === 'unsuspend'">
<div>{{ i18n.ts.user }}: {{ log.info.targetId }}</div>
</template>
<template v-else-if="log.type === 'assignRole'">
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
<div>{{ i18n.ts.role }}: {{ log.info.roleName }} [{{ log.info.roleId }}]</div>
</template>
<template v-else-if="log.type === 'unassignRole'">
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
<div>{{ i18n.ts.role }}: {{ log.info.roleName }} [{{ log.info.roleId }}]</div>
</template>
</div>
</MkFolder>
</template>
<script lang="ts" setup>
import * as Misskey from 'misskey-js';
import { CodeDiff } from 'v-code-diff';
import JSON5 from 'json5';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { dateString } from '@/filters/date.js';
import MkFolder from '@/components/MkFolder.vue';
const props = defineProps<{
log: Misskey.entities.ModerationLog;
}>();
</script>
<style lang="scss" module>
.root {
}
.avatar {
width: 18px;
height: 18px;
}
.diff {
background: #fff;
color: #000;
border-radius: 6px;
overflow: clip;
}
</style>

View File

@@ -0,0 +1,67 @@
<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer>
<template #header><XHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="900">
<div>
<div style="display: flex; gap: var(--margin); flex-wrap: wrap;">
<MkSelect v-model="type" style="margin: 0; flex: 1;">
<template #label>{{ i18n.ts.type }}</template>
<option :value="null">{{ i18n.ts.all }}</option>
<option v-for="t in Misskey.moderationLogTypes" :key="t" :value="t">{{ i18n.ts._moderationLogTypes[t] ?? t }}</option>
</MkSelect>
<MkInput v-model="moderatorId" style="margin: 0; flex: 1;">
<template #label>{{ i18n.ts.moderator }}(ID)</template>
</MkInput>
</div>
<MkPagination v-slot="{items}" ref="logs" :pagination="pagination" style="margin-top: var(--margin);">
<div class="_gaps_s">
<XModLog v-for="item in items" :key="item.id" :log="item"/>
</div>
</MkPagination>
</div>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import * as Misskey from 'misskey-js';
import XHeader from './_header_.vue';
import XModLog from './modlog.ModLog.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkInput from '@/components/MkInput.vue';
import MkPagination from '@/components/MkPagination.vue';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let logs = $shallowRef<InstanceType<typeof MkPagination>>();
let type = $ref(null);
let moderatorId = $ref('');
const pagination = {
endpoint: 'admin/show-moderation-logs' as const,
limit: 30,
params: computed(() => ({
type,
userId: moderatorId === '' ? null : moderatorId,
})),
};
console.log(Misskey);
const headerActions = $computed(() => []);
const headerTabs = $computed(() => []);
definePageMetadata({
title: i18n.ts.moderationLogs,
icon: 'ti ti-list-search',
});
</script>

View File

@@ -89,10 +89,10 @@ import MkSwitch from '@/components/MkSwitch.vue';
import MkInput from '@/components/MkInput.vue';
import FormSuspense from '@/components/form/suspense.vue';
import FormSplit from '@/components/form/split.vue';
import * as os from '@/os';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
let useObjectStorage: boolean = $ref(false);

View File

@@ -46,10 +46,10 @@ SPDX-License-Identifier: AGPL-3.0-only
import { } from 'vue';
import XHeader from './_header_.vue';
import FormSuspense from '@/components/form/suspense.vue';
import * as os from '@/os';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkSwitch from '@/components/MkSwitch.vue';
let enableServerMachineStats: boolean = $ref(false);

View File

@@ -16,11 +16,11 @@ SPDX-License-Identifier: AGPL-3.0-only
import { onMounted } from 'vue';
import { Chart } from 'chart.js';
import gradient from 'chartjs-plugin-gradient';
import * as os from '@/os';
import { defaultStore } from '@/store';
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { chartVLine } from '@/scripts/chart-vline';
import { initChart } from '@/scripts/init-chart';
import * as os from '@/os.js';
import { defaultStore } from '@/store.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
import { chartVLine } from '@/scripts/chart-vline.js';
import { initChart } from '@/scripts/init-chart.js';
initChart();

View File

@@ -23,12 +23,12 @@ SPDX-License-Identifier: AGPL-3.0-only
import { onMounted } from 'vue';
import { Chart } from 'chart.js';
import gradient from 'chartjs-plugin-gradient';
import * as os from '@/os';
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { chartVLine } from '@/scripts/chart-vline';
import { defaultStore } from '@/store';
import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart';
import * as os from '@/os.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
import { chartVLine } from '@/scripts/chart-vline.js';
import { defaultStore } from '@/store.js';
import { alpha } from '@/scripts/color.js';
import { initChart } from '@/scripts/init-chart.js';
initChart();

View File

@@ -48,11 +48,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted } from 'vue';
import XPie from './overview.pie.vue';
import * as os from '@/os';
import number from '@/filters/number';
import * as os from '@/os.js';
import number from '@/filters/number.js';
import MkNumberDiff from '@/components/MkNumberDiff.vue';
import { i18n } from '@/i18n';
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { i18n } from '@/i18n.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
let topSubInstancesForPie: any = $ref(null);
let topPubInstancesForPie: any = $ref(null);

View File

@@ -18,10 +18,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
import * as os from '@/os.js';
import { useInterval } from '@/scripts/use-interval.js';
import MkInstanceCardMini from '@/components/MkInstanceCardMini.vue';
import { defaultStore } from '@/store';
import { defaultStore } from '@/store.js';
const instances = ref([]);
const fetching = ref(true);

View File

@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in">
<MkLoading v-if="fetching"/>
<div v-else :class="$style.root" class="_panel">
<MkA v-for="user in moderators" :key="user.id" class="user" :to="`/user-info/${user.id}`">
<MkA v-for="user in moderators" :key="user.id" class="user" :to="`/admin/user/${user.id}`">
<MkAvatar :user="user" class="avatar" indicator/>
</MkA>
</div>
@@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted } from 'vue';
import * as os from '@/os';
import { defaultStore } from '@/store';
import * as os from '@/os.js';
import { defaultStore } from '@/store.js';
let moderators: any = $ref(null);
let fetching = $ref(true);

View File

@@ -10,8 +10,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted, shallowRef } from 'vue';
import { Chart } from 'chart.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { initChart } from '@/scripts/init-chart';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
import { initChart } from '@/scripts/init-chart.js';
initChart();

View File

@@ -10,11 +10,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted, shallowRef } from 'vue';
import { Chart } from 'chart.js';
import { defaultStore } from '@/store';
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart';
import { defaultStore } from '@/store.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
import { chartVLine } from '@/scripts/chart-vline.js';
import { alpha } from '@/scripts/color.js';
import { initChart } from '@/scripts/init-chart.js';
initChart();

View File

@@ -37,8 +37,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { markRaw, onMounted, onUnmounted, ref } from 'vue';
import XChart from './overview.queue.chart.vue';
import number from '@/filters/number';
import { useStream } from '@/stream';
import number from '@/filters/number.js';
import { useStream } from '@/stream.js';
const connection = markRaw(useStream().useChannel('queueStats'));

View File

@@ -62,12 +62,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted } from 'vue';
import * as os from '@/os';
import * as os from '@/os.js';
import MkNumberDiff from '@/components/MkNumberDiff.vue';
import MkNumber from '@/components/MkNumber.vue';
import { i18n } from '@/i18n';
import { customEmojis } from '@/custom-emojis';
import { defaultStore } from '@/store';
import { i18n } from '@/i18n.js';
import { customEmojis } from '@/custom-emojis.js';
import { defaultStore } from '@/store.js';
let stats: any = $ref(null);
let usersComparedToThePrevDay = $ref<number>();

View File

@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" mode="out-in">
<MkLoading v-if="fetching"/>
<div v-else class="users">
<MkA v-for="(user, i) in newUsers" :key="user.id" :to="`/user-info/${user.id}`" class="user">
<MkA v-for="(user, i) in newUsers" :key="user.id" :to="`/admin/user/${user.id}`" class="user">
<MkUserCardMini :user="user"/>
</MkA>
</div>
@@ -17,10 +17,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
import * as os from '@/os.js';
import { useInterval } from '@/scripts/use-interval.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import { defaultStore } from '@/store';
import { defaultStore } from '@/store.js';
let newUsers = $ref(null);
let fetching = $ref(true);

View File

@@ -76,10 +76,10 @@ import XStats from './overview.stats.vue';
import XRetention from './overview.retention.vue';
import XModerators from './overview.moderators.vue';
import XHeatmap from './overview.heatmap.vue';
import * as os from '@/os';
import { useStream } from '@/stream';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { useStream } from '@/stream.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
const rootEl = $shallowRef<HTMLElement>();

View File

@@ -26,10 +26,10 @@ 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';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let proxyAccount: any = $ref(null);
let proxyAccountId: any = $ref(null);

View File

@@ -10,11 +10,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted, shallowRef } from 'vue';
import { Chart } from 'chart.js';
import { defaultStore } from '@/store';
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
import { chartVLine } from '@/scripts/chart-vline';
import { alpha } from '@/scripts/color';
import { initChart } from '@/scripts/init-chart';
import { defaultStore } from '@/store.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js';
import { chartVLine } from '@/scripts/chart-vline.js';
import { alpha } from '@/scripts/color.js';
import { initChart } from '@/scripts/init-chart.js';
initChart();

View File

@@ -50,10 +50,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { markRaw, onMounted, onUnmounted, ref } from 'vue';
import XChart from './queue.chart.chart.vue';
import number from '@/filters/number';
import * as os from '@/os';
import { useStream } from '@/stream';
import { i18n } from '@/i18n';
import number from '@/filters/number.js';
import * as os from '@/os.js';
import { useStream } from '@/stream.js';
import { i18n } from '@/i18n.js';
import MkFolder from '@/components/MkFolder.vue';
const connection = markRaw(useStream().useChannel('queueStats'));

View File

@@ -18,10 +18,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import XQueue from './queue.chart.vue';
import XHeader from './_header_.vue';
import * as os from '@/os';
import * as config from '@/config';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import * as config from '@/config.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
let tab = $ref('deliver');

View File

@@ -27,9 +27,9 @@ SPDX-License-Identifier: AGPL-3.0-only
import { } from 'vue';
import XHeader from './_header_.vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let relays: any[] = $ref([]);

View File

@@ -26,10 +26,10 @@ import { computed } from 'vue';
import { v4 as uuid } from 'uuid';
import XHeader from './_header_.vue';
import XEditor from './roles.editor.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { useRouter } from '@/router';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { useRouter } from '@/router.js';
import MkButton from '@/components/MkButton.vue';
import { rolesCache } from '@/cache';

View File

@@ -568,10 +568,10 @@ import MkFolder from '@/components/MkFolder.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkRange from '@/components/MkRange.vue';
import FormSlot from '@/components/form/slot.vue';
import { i18n } from '@/i18n';
import { i18n } from '@/i18n.js';
import { ROLE_POLICIES } from '@/const';
import { instance } from '@/instance';
import { deepClone } from '@/scripts/clone';
import { instance } from '@/instance.js';
import { deepClone } from '@/scripts/clone.js';
const emit = defineEmits<{
(ev: 'update:modelValue', v: any): void;

View File

@@ -37,7 +37,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_s">
<div v-for="item in items" :key="item.user.id" :class="[$style.userItem, { [$style.userItemOpend]: expandedItems.includes(item.id) }]">
<div :class="$style.userItemMain">
<MkA :class="$style.userItemMainBody" :to="`/user-info/${item.user.id}`">
<MkA :class="$style.userItemMainBody" :to="`/admin/user/${item.user.id}`">
<MkUserCardMini :user="item.user"/>
</MkA>
<button class="_button" :class="$style.userToggle" @click="toggleItem(item)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button>
@@ -66,15 +66,15 @@ import { computed, reactive } from 'vue';
import XHeader from './_header_.vue';
import XEditor from './roles.editor.vue';
import MkFolder from '@/components/MkFolder.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { useRouter } from '@/router';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { useRouter } from '@/router.js';
import MkButton from '@/components/MkButton.vue';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkPagination, { Paging } from '@/components/MkPagination.vue';
import { infoImageUrl } from '@/instance';
import { infoImageUrl } from '@/instance.js';
const router = useRouter();

View File

@@ -233,11 +233,11 @@ import MkSwitch from '@/components/MkSwitch.vue';
import MkButton from '@/components/MkButton.vue';
import MkRange from '@/components/MkRange.vue';
import MkRolePreview from '@/components/MkRolePreview.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { instance } from '@/instance';
import { useRouter } from '@/router';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { instance } from '@/instance.js';
import { useRouter } from '@/router.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { ROLE_POLICIES } from '@/const';

View File

@@ -117,10 +117,10 @@ import FormSuspense from '@/components/form/suspense.vue';
import MkRange from '@/components/MkRange.vue';
import MkInput from '@/components/MkInput.vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let summalyProxy: string = $ref('');
let enableHcaptcha: boolean = $ref(false);

View File

@@ -43,10 +43,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { defineAsyncComponent } from 'vue';
import XHeader from './_header_.vue';
import * as os from '@/os';
import { fetchInstance, instance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance, instance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';

View File

@@ -14,6 +14,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.instanceName }}</template>
</MkInput>
<MkInput v-model="shortName">
<template #label>{{ i18n.ts._serverSettings.shortName }} ({{ i18n.ts.optional }})</template>
<template #caption>{{ i18n.ts._serverSettings.shortNameDescription }}</template>
</MkInput>
<MkTextarea v-model="description">
<template #label>{{ i18n.ts.instanceDescription }}</template>
</MkTextarea>
@@ -40,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_m">
<MkSwitch v-model="cacheRemoteFiles">
<template #label>{{ i18n.ts.cacheRemoteFiles }}</template>
<template #caption>{{ i18n.ts.cacheRemoteFilesDescription }}</template>
<template #caption>{{ i18n.ts.cacheRemoteFilesDescription }}{{ i18n.ts.youCanCleanRemoteFilesCache }}</template>
</MkSwitch>
<template v-if="cacheRemoteFiles">
@@ -111,13 +116,14 @@ import MkTextarea from '@/components/MkTextarea.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';
import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { fetchInstance } from '@/instance.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkButton from '@/components/MkButton.vue';
let name: string | null = $ref(null);
let shortName: string | null = $ref(null);
let description: string | null = $ref(null);
let maintainerName: string | null = $ref(null);
let maintainerEmail: string | null = $ref(null);
@@ -133,6 +139,7 @@ let deeplIsPro: boolean = $ref(false);
async function init(): Promise<void> {
const meta = await os.api('admin/meta');
name = meta.name;
shortName = meta.shortName;
description = meta.description;
maintainerName = meta.maintainerName;
maintainerEmail = meta.maintainerEmail;
@@ -149,6 +156,7 @@ async function init(): Promise<void> {
function save(): void {
os.apiWithDialog('admin/update-meta', {
name,
shortName: shortName === '' ? null : shortName,
description,
maintainerName,
maintainerEmail,

View File

@@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkPagination v-slot="{items}" ref="paginationComponent" :pagination="pagination">
<div :class="$style.users">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" :class="$style.user" :to="`/user-info/${user.id}`">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" :class="$style.user" :to="`/admin/user/${user.id}`">
<MkUserCardMini :user="user"/>
</MkA>
</div>
@@ -62,12 +62,12 @@ import XHeader from './_header_.vue';
import MkInput from '@/components/MkInput.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkPagination from '@/components/MkPagination.vue';
import * as os from '@/os';
import { lookupUser } from '@/scripts/lookup-user';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { lookupUser } from '@/scripts/lookup-user.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import { dateString } from '@/filters/date';
import { dateString } from '@/filters/date.js';
let paginationComponent = $shallowRef<InstanceType<typeof MkPagination>>();
@@ -116,7 +116,7 @@ async function addUser() {
}
function show(user) {
os.pageWindow(`/user-info/${user.id}`);
os.pageWindow(`/admin/user/${user.id}`);
}
const headerActions = $computed(() => [{

View File

@@ -17,10 +17,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, watch } from 'vue';
import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { instance } from '@/instance';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js';
definePageMetadata({
title: i18n.ts.ads,

View File

@@ -41,13 +41,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref, watch } from 'vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { $i, updateAccount } from '@/account';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import MkInfo from '@/components/MkInfo.vue';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { $i, updateAccount } from '@/account.js';
const paginationCurrent = {
endpoint: 'announcements' as const,
@@ -68,6 +68,7 @@ const paginationPast = {
};
const paginationEl = ref<InstanceType<typeof MkPagination>>();
const tab = ref('current');
async function read(announcement): Promise<void> {

View File

@@ -26,11 +26,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, watch } from 'vue';
import MkTimeline from '@/components/MkTimeline.vue';
import { scroll } from '@/scripts/scroll';
import * as os from '@/os';
import { useRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { scroll } from '@/scripts/scroll.js';
import * as os from '@/os.js';
import { useRouter } from '@/router.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
const router = useRouter();

View File

@@ -41,8 +41,8 @@ import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const body = ref('{}');
const endpoint = ref('');

View File

@@ -21,13 +21,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
import { AuthSession } from 'misskey-js/built/entities';
import * as Misskey from 'misskey-js';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
session: AuthSession;
session: Misskey.entities.AuthSession;
}>();
const emit = defineEmits<{
@@ -58,7 +58,6 @@ function accept() {
emit('accepted');
});
}
</script>
<style lang="scss" module>

View File

@@ -43,20 +43,20 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { onMounted } from 'vue';
import { AuthSession } from 'misskey-js/built/entities';
import * as Misskey from 'misskey-js';
import XForm from './auth.form.vue';
import MkSignin from '@/components/MkSignin.vue';
import * as os from '@/os';
import { $i, login } from '@/account';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { $i, login } from '@/account.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
token: string;
}>();
let state = $ref<'waiting' | 'accepted' | 'fetch-session-error' | 'denied' | null>(null);
let session = $ref<AuthSession | null>(null);
let session = $ref<Misskey.entities.AuthSession | null>(null);
function accepted() {
state = 'accepted';

View File

@@ -20,6 +20,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.color }}</template>
</MkColorInput>
<MkSwitch v-model="isSensitive">
<template #label>{{ i18n.ts.sensitive }}</template>
</MkSwitch>
<div>
<MkButton v-if="bannerId == null" @click="setBannerImage"><i class="ti ti-plus"></i> {{ i18n.ts._channel.setBanner }}</MkButton>
<div v-else-if="bannerUrl">
@@ -66,12 +70,13 @@ import MkTextarea from '@/components/MkTextarea.vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkColorInput from '@/components/MkColorInput.vue';
import { selectFile } from '@/scripts/select-file';
import * as os from '@/os';
import { useRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { selectFile } from '@/scripts/select-file.js';
import * as os from '@/os.js';
import { useRouter } from '@/router.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
import MkFolder from '@/components/MkFolder.vue';
import MkSwitch from "@/components/MkSwitch.vue";
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
@@ -87,6 +92,7 @@ let description = $ref(null);
let bannerUrl = $ref<string | null>(null);
let bannerId = $ref<string | null>(null);
let color = $ref('#000');
let isSensitive = $ref(false);
const pinnedNotes = ref([]);
watch(() => bannerId, async () => {
@@ -110,6 +116,7 @@ async function fetchChannel() {
description = channel.description;
bannerId = channel.bannerId;
bannerUrl = channel.bannerUrl;
isSensitive = channel.isSensitive;
pinnedNotes.value = channel.pinnedNoteIds.map(id => ({
id,
}));
@@ -142,6 +149,7 @@ function save() {
bannerId: bannerId,
pinnedNoteIds: pinnedNotes.value.map(x => x.id),
color: color,
isSensitive: isSensitive,
};
if (props.channelId) {

View File

@@ -17,6 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div><i class="ti ti-users ti-fw"></i><I18n :src="i18n.ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div>
<div><i class="ti ti-pencil ti-fw"></i><I18n :src="i18n.ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div>
</div>
<div v-if="channel.isSensitive" :class="$style.sensitiveIndicator">{{ i18n.ts.sensitive }}</div>
<div :class="$style.bannerFade"></div>
</div>
<div v-if="channel.description" :class="$style.description">
@@ -71,17 +72,17 @@ import { computed, watch } from 'vue';
import MkPostForm from '@/components/MkPostForm.vue';
import MkTimeline from '@/components/MkTimeline.vue';
import XChannelFollowButton from '@/components/MkChannelFollowButton.vue';
import * as os from '@/os';
import { useRouter } from '@/router';
import { $i, iAmModerator } from '@/account';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { deviceKind } from '@/scripts/device-kind';
import * as os from '@/os.js';
import { useRouter } from '@/router.js';
import { $i, iAmModerator } from '@/account.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { deviceKind } from '@/scripts/device-kind.js';
import MkNotes from '@/components/MkNotes.vue';
import { url } from '@/config';
import { url } from '@/config.js';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import { defaultStore } from '@/store';
import { defaultStore } from '@/store.js';
import MkNote from '@/components/MkNote.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
@@ -274,4 +275,17 @@ definePageMetadata(computed(() => channel ? {
.description {
padding: 16px;
}
.sensitiveIndicator {
position: absolute;
z-index: 1;
bottom: 16px;
left: 16px;
background: rgba(0, 0, 0, 0.7);
color: var(--warn);
border-radius: 6px;
font-weight: bold;
font-size: 1em;
padding: 4px 7px;
}
</style>

View File

@@ -58,9 +58,9 @@ import MkInput from '@/components/MkInput.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkButton from '@/components/MkButton.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { useRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { useRouter } from '@/router.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
const router = useRouter();

View File

@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import MkClickerGame from '@/components/MkClickerGame.vue';
import { definePageMetadata } from '@/scripts/page-metadata';
import { definePageMetadata } from '@/scripts/page-metadata.js';
definePageMetadata({
title: '🍪👈',

View File

@@ -27,13 +27,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, watch, provide } from 'vue';
import * as misskey from 'misskey-js';
import * as Misskey from 'misskey-js';
import MkNotes from '@/components/MkNotes.vue';
import { $i } from '@/account';
import { i18n } from '@/i18n';
import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata';
import { url } from '@/config';
import { $i } from '@/account.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { url } from '@/config.js';
import MkButton from '@/components/MkButton.vue';
import { clipsCache } from '@/cache';
@@ -41,7 +41,7 @@ const props = defineProps<{
clipId: string,
}>();
let clip: misskey.entities.Clip = $ref<misskey.entities.Clip>();
let clip: Misskey.entities.Clip = $ref<Misskey.entities.Clip>();
let favorited = $ref(false);
const pagination = {
endpoint: 'clips/notes' as const,

View File

@@ -80,10 +80,10 @@ import MkInput from '@/components/MkInput.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import FormSplit from '@/components/form/split.vue';
import { selectFile, selectFiles } from '@/scripts/select-file';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { selectFile, selectFiles } from '@/scripts/select-file.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const emojisPaginationComponent = shallowRef<InstanceType<typeof MkPagination>>();

View File

@@ -12,8 +12,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed } from 'vue';
import XDrive from '@/components/MkDrive.vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
let folder = $ref(null);

View File

@@ -92,18 +92,18 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, watch } from 'vue';
import * as misskey from 'misskey-js';
import * as Misskey from 'misskey-js';
import MkModalWindow from '@/components/MkModalWindow.vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkInfo from '@/components/MkInfo.vue';
import MkFolder from '@/components/MkFolder.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { customEmojiCategories } from '@/custom-emojis';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { customEmojiCategories } from '@/custom-emojis.js';
import MkSwitch from '@/components/MkSwitch.vue';
import { selectFile, selectFiles } from '@/scripts/select-file';
import { selectFile, selectFiles } from '@/scripts/select-file.js';
import MkRolePreview from '@/components/MkRolePreview.vue';
const props = defineProps<{
@@ -121,7 +121,7 @@ let roleIdsThatCanBeUsedThisEmojiAsReaction = $ref(props.emoji ? props.emoji.rol
let rolesThatCanBeUsedThisEmojiAsReaction = $ref([]);
let roleIdsThatCanNotBeUsedThisEmojiAsReaction = $ref(props.emoji ? props.emoji.roleIdsThatCanNotBeUsedThisEmojiAsReaction : []);
let rolesThatCanNotBeUsedThisEmojiAsReaction = $ref([]);
let file = $ref<misskey.entities.DriveFile>();
let file = $ref<Misskey.entities.DriveFile>();
watch($$(roleIdsThatCanBeUsedThisEmojiAsReaction), async () => {
rolesThatCanBeUsedThisEmojiAsReaction = (await Promise.all(roleIdsThatCanBeUsedThisEmojiAsReaction.map((id) => os.api('admin/roles/show', { roleId: id }).catch(() => null)))).filter(x => x != null);

View File

@@ -15,9 +15,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
import * as os from '@/os';
import copyToClipboard from '@/scripts/copy-to-clipboard';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import copyToClipboard from '@/scripts/copy-to-clipboard.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
emoji: {

View File

@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import MkNotes from '@/components/MkNotes.vue';
import MkTab from '@/components/MkTab.vue';
import { i18n } from '@/i18n';
import { i18n } from '@/i18n.js';
const paginationForNotes = {
endpoint: 'notes/featured' as const,

View File

@@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
import MkRolePreview from '@/components/MkRolePreview.vue';
import * as os from '@/os';
import * as os from '@/os.js';
let roles = $ref();

View File

@@ -67,8 +67,8 @@ import { watch } from 'vue';
import MkUserList from '@/components/MkUserList.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkTab from '@/components/MkTab.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
tag?: string;

View File

@@ -26,8 +26,8 @@ import XFeatured from './explore.featured.vue';
import XUsers from './explore.users.vue';
import XRoles from './explore.roles.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{
tag?: string;

View File

@@ -29,9 +29,9 @@ SPDX-License-Identifier: AGPL-3.0-only
import MkPagination from '@/components/MkPagination.vue';
import MkNote from '@/components/MkNote.vue';
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { infoImageUrl } from '@/instance';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { infoImageUrl } from '@/instance.js';
const pagination = {
endpoint: 'i/favorites' as const,

View File

@@ -23,6 +23,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton @click="show"><i class="ti ti-eye"></i> {{ i18n.ts.show }}</MkButton>
<MkButton v-if="flash" danger @click="del"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
</div>
<MkSelect v-model="visibility">
<template #label>{{ i18n.ts.visibility }}</template>
<option :key="'public'" :value="'public'">{{ i18n.ts.public }}</option>
<option :key="'private'" :value="'private'">{{ i18n.ts.private }}</option>
</MkSelect>
</div>
</MkSpacer>
</MkStickyContainer>
@@ -31,14 +36,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed } from 'vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkTextarea from '@/components/MkTextarea.vue';
import MkInput from '@/components/MkInput.vue';
import { useRouter } from '@/router';
import MkSelect from '@/components/MkSelect.vue';
import { useRouter } from '@/router.js';
const PRESET_DEFAULT = `/// @ 0.15.0
const PRESET_DEFAULT = `/// @ 0.16.0
var name = ""
@@ -56,7 +62,7 @@ Ui:render([
])
`;
const PRESET_OMIKUJI = `/// @ 0.15.0
const PRESET_OMIKUJI = `/// @ 0.16.0
// ユーザーごとに日替わりのおみくじのプリセット
// 選択肢
@@ -99,7 +105,7 @@ Ui:render([
])
`;
const PRESET_SHUFFLE = `/// @ 0.15.0
const PRESET_SHUFFLE = `/// @ 0.16.0
// 巻き戻し可能な文字シャッフルのプリセット
let string = "ペペロンチーノ"
@@ -178,7 +184,7 @@ var cursor = 0
do()
`;
const PRESET_QUIZ = `/// @ 0.15.0
const PRESET_QUIZ = `/// @ 0.16.0
let title = '地理クイズ'
let qas = [{
@@ -291,7 +297,7 @@ qaEls.push(Ui:C:container({
Ui:render(qaEls)
`;
const PRESET_TIMELINE = `/// @ 0.15.0
const PRESET_TIMELINE = `/// @ 0.16.0
// APIリクエストを行いローカルタイムラインを表示するプリセット
@fetch() {
@@ -358,6 +364,7 @@ const props = defineProps<{
}>();
let flash = $ref(null);
let visibility = $ref('public');
if (props.id) {
flash = await os.api('flash/show', {
@@ -402,6 +409,7 @@ async function save() {
summary,
permissions,
script,
visibility,
});
} else {
const created = await os.apiWithDialog('flash/create', {

View File

@@ -42,9 +42,9 @@ import { computed } from 'vue';
import MkFlashPreview from '@/components/MkFlashPreview.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import { useRouter } from '@/router';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { useRouter } from '@/router.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const router = useRouter();

View File

@@ -59,17 +59,17 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed, onDeactivated, onUnmounted, Ref, ref, watch } from 'vue';
import { Interpreter, Parser, values } from '@syuilo/aiscript';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { url } from '@/config';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { url } from '@/config.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import MkAsUi from '@/components/MkAsUi.vue';
import { AsUiComponent, AsUiRoot, registerAsUiLib } from '@/scripts/aiscript/ui';
import { createAiScriptEnv } from '@/scripts/aiscript/api';
import { AsUiComponent, AsUiRoot, registerAsUiLib } from '@/scripts/aiscript/ui.js';
import { createAiScriptEnv } from '@/scripts/aiscript/api.js';
import MkFolder from '@/components/MkFolder.vue';
import MkCode from '@/components/MkCode.vue';
import { defaultStore } from '@/store';
import { $i } from '@/account';
import { defaultStore } from '@/store.js';
import { $i } from '@/account.js';
const props = defineProps<{
id: string;

View File

@@ -40,11 +40,11 @@ SPDX-License-Identifier: AGPL-3.0-only
import { shallowRef, computed } from 'vue';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import { userPage, acct } from '@/filters/user';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { infoImageUrl } from '@/instance';
import { userPage, acct } from '@/filters/user.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { infoImageUrl } from '@/instance.js';
const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();

View File

@@ -10,10 +10,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
import * as Acct from 'misskey-js/built/acct';
import * as os from '@/os';
import { mainRouter } from '@/router';
import { i18n } from '@/i18n';
import * as Misskey from 'misskey-js';
import * as os from '@/os.js';
import { mainRouter } from '@/router.js';
import { i18n } from '@/i18n.js';
async function follow(user): Promise<void> {
const { canceled } = await os.confirm({
@@ -57,7 +57,7 @@ if (acct.startsWith('https://')) {
}
});
} else {
promise = os.api('users/show', Acct.parse(acct));
promise = os.api('users/show', Misskey.acct.parse(acct));
promise.then(user => {
follow(user);
});

View File

@@ -44,11 +44,11 @@ import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import FormSuspense from '@/components/form/suspense.vue';
import { selectFiles } from '@/scripts/select-file';
import * as os from '@/os';
import { useRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { selectFiles } from '@/scripts/select-file.js';
import * as os from '@/os.js';
import { useRouter } from '@/router.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
const router = useRouter();

View File

@@ -51,9 +51,9 @@ import { watch } from 'vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { useRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
import { useRouter } from '@/router.js';
const router = useRouter();

View File

@@ -63,17 +63,17 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, watch } from 'vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import * as os from '@/os.js';
import MkContainer from '@/components/MkContainer.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue';
import MkFollowButton from '@/components/MkFollowButton.vue';
import { url } from '@/config';
import { useRouter } from '@/router';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { defaultStore } from '@/store';
import { $i } from '@/account';
import { url } from '@/config.js';
import { useRouter } from '@/router.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { defaultStore } from '@/store.js';
import { $i } from '@/account.js';
const router = useRouter();

View File

@@ -102,7 +102,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div v-else-if="tab === 'users'" class="_gaps_m">
<MkPagination v-slot="{items}" :pagination="usersPagination" style="display: grid; grid-template-columns: repeat(auto-fill,minmax(270px,1fr)); grid-gap: 12px;">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" class="user" :to="`/user-info/${user.id}`">
<MkA v-for="user in items" :key="user.id" v-tooltip.mfm="`Last posted: ${dateString(user.updatedAt)}`" class="user" :to="`/admin/user/${user.id}`">
<MkUserCardMini :user="user"/>
</MkA>
</MkPagination>
@@ -117,7 +117,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { } from 'vue';
import * as misskey from 'misskey-js';
import * as Misskey from 'misskey-js';
import MkChart from '@/components/MkChart.vue';
import MkObjectView from '@/components/MkObjectView.vue';
import FormLink from '@/components/form/link.vue';
@@ -127,15 +127,15 @@ import FormSection from '@/components/form/section.vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import * as os from '@/os';
import number from '@/filters/number';
import { iAmModerator, iAmAdmin } from '@/account';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import number from '@/filters/number.js';
import { iAmModerator, iAmAdmin } from '@/account.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkPagination from '@/components/MkPagination.vue';
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy';
import { dateString } from '@/filters/date';
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
import { dateString } from '@/filters/date.js';
const props = defineProps<{
host: string;
@@ -143,8 +143,8 @@ const props = defineProps<{
let tab = $ref('overview');
let chartSrc = $ref('instance-requests');
let meta = $ref<misskey.entities.AdminInstanceMetadata | null>(null);
let instance = $ref<misskey.entities.Instance | null>(null);
let meta = $ref<Misskey.entities.AdminInstanceMetadata | null>(null);
let instance = $ref<Misskey.entities.Instance | null>(null);
let suspended = $ref(false);
let isBlocked = $ref(false);
let faviconUrl = $ref<string | null>(null);

View File

@@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkPagination ref="pagingComponent" :pagination="pagination">
<template #default="{ items }">
<div class="_gaps_s">
<MkInviteCode v-for="item in (items as Invite[])" :key="item.id" :invite="item" :onDeleted="deleted"/>
<MkInviteCode v-for="item in (items as Misskey.entities.Invite[])" :key="item.id" :invite="item" :onDeleted="deleted"/>
</div>
</template>
</MkPagination>
@@ -37,15 +37,15 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, ref, shallowRef } from 'vue';
import type { Invite } from 'misskey-js/built/entities';
import { i18n } from '@/i18n';
import * as os from '@/os';
import type * as Misskey from 'misskey-js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import MkButton from '@/components/MkButton.vue';
import MkPagination, { Paging } from '@/components/MkPagination.vue';
import MkInviteCode from '@/components/MkInviteCode.vue';
import { definePageMetadata } from '@/scripts/page-metadata';
import { serverErrorImageUrl, instance } from '@/instance';
import { $i } from '@/account';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { serverErrorImageUrl, instance } from '@/instance.js';
import { $i } from '@/account.js';
const pagingComponent = shallowRef<InstanceType<typeof MkPagination>>();
const currentInviteLimit = ref<null | number>(null);

View File

@@ -35,13 +35,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { watch, computed } from 'vue';
import * as os from '@/os';
import { userPage } from '@/filters/user';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { userPage } from '@/filters/user.js';
import { i18n } from '@/i18n.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkButton from '@/components/MkButton.vue';
import { definePageMetadata } from '@/scripts/page-metadata';
import { serverErrorImageUrl } from '@/instance';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { serverErrorImageUrl } from '@/instance.js';
const props = defineProps<{
listId: string;

View File

@@ -46,10 +46,10 @@ SPDX-License-Identifier: AGPL-3.0-only
import { } from 'vue';
import MkSignin from '@/components/MkSignin.vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { $i, login } from '@/account';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { $i, login } from '@/account.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const props = defineProps<{
session: string;

View File

@@ -11,9 +11,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import XAntenna from './editor.vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { useRouter } from '@/router';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { useRouter } from '@/router.js';
import { antennasCache } from '@/cache';
const router = useRouter();

View File

@@ -11,10 +11,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import XAntenna from './editor.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { useRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { useRouter } from '@/router.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { antennasCache } from '@/cache';
const router = useRouter();

View File

@@ -16,12 +16,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<!--<option value="home">{{ i18n.ts._antennaSources.homeTimeline }}</option>-->
<option value="users">{{ i18n.ts._antennaSources.users }}</option>
<!--<option value="list">{{ i18n.ts._antennaSources.userList }}</option>-->
<option value="users_blacklist">{{ i18n.ts._antennaSources.userBlacklist }}</option>
</MkSelect>
<MkSelect v-if="src === 'list'" v-model="userListId">
<template #label>{{ i18n.ts.userList }}</template>
<option v-for="list in userLists" :key="list.id" :value="list.id">{{ list.name }}</option>
</MkSelect>
<MkTextarea v-else-if="src === 'users'" v-model="users">
<MkTextarea v-else-if="src === 'users' || src === 'users_blacklist'" v-model="users">
<template #label>{{ i18n.ts.users }}</template>
<template #caption>{{ i18n.ts.antennaUsersDescription }} <button class="_textButton" @click="addUser">{{ i18n.ts.addUser }}</button></template>
</MkTextarea>
@@ -48,14 +49,14 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { watch } from 'vue';
import * as Acct from 'misskey-js/built/acct';
import * as Misskey from 'misskey-js';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
antenna: any
@@ -127,7 +128,7 @@ async function deleteAntenna() {
function addUser() {
os.selectUser().then(user => {
users = users.trim();
users += '\n@' + Acct.toString(user as any);
users += '\n@' + Misskey.acct.toString(user as any);
users = users.trim();
});
}

View File

@@ -28,18 +28,17 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { antennasCache } from '@/cache';
import { api } from '@/os';
import { onActivated } from 'vue';
import { infoImageUrl } from '@/instance';
import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { antennasCache } from '@/cache';
import { infoImageUrl } from '@/instance.js';
const antennas = $computed(() => antennasCache.value.value ?? []);
function fetch() {
antennasCache.fetch(() => api('antennas/list'));
antennasCache.fetch();
}
fetch();
@@ -62,7 +61,7 @@ definePageMetadata({
});
onActivated(() => {
antennasCache.fetch(() => api('antennas/list'));
antennasCache.fetch();
});
</script>

View File

@@ -30,9 +30,9 @@ import { watch } from 'vue';
import MkPagination from '@/components/MkPagination.vue';
import MkButton from '@/components/MkButton.vue';
import MkClipPreview from '@/components/MkClipPreview.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { clipsCache } from '@/cache';
const pagination = {

View File

@@ -32,17 +32,17 @@ SPDX-License-Identifier: AGPL-3.0-only
import { onActivated } from 'vue';
import MkButton from '@/components/MkButton.vue';
import MkAvatars from '@/components/MkAvatars.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { userListsCache } from '@/cache';
import { infoImageUrl } from '@/instance';
import { $i } from '@/account';
import { infoImageUrl } from '@/instance.js';
import { $i } from '@/account.js';
const items = $computed(() => userListsCache.value.value ?? []);
function fetch() {
userListsCache.fetch(() => os.api('users/lists/list'));
userListsCache.fetch();
}
fetch();

View File

@@ -48,20 +48,20 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import * as Misskey from 'misskey-js';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { mainRouter } from '@/router';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { userPage } from '@/filters/user';
import * as os from '@/os.js';
import { mainRouter } from '@/router.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
import { userPage } from '@/filters/user.js';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkInput from '@/components/MkInput.vue';
import { userListsCache } from '@/cache';
import { UserList, UserLite } from 'misskey-js/built/entities';
import { $i } from '@/account';
import { defaultStore } from '@/store';
import { $i } from '@/account.js';
import { defaultStore } from '@/store.js';
const {
enableInfiniteScroll,
} = defaultStore.reactiveState;
@@ -72,8 +72,8 @@ const props = defineProps<{
const FETCH_USERS_LIMIT = 20;
let list = $ref<UserList | null>(null);
let users = $ref<UserLite[]>([]);
let list = $ref<Misskey.entities.UserList | null>(null);
let users = $ref<Misskey.entities.UserLite[]>([]);
let queueUserIds = $ref<string[]>([]);
let fetching = $ref(true);
const isPublic = ref(false);

View File

@@ -13,10 +13,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
<script lang="ts" setup>
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { pleaseLogin } from '@/scripts/please-login';
import { notFoundImageUrl } from '@/instance';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { pleaseLogin } from '@/scripts/please-login.js';
import { notFoundImageUrl } from '@/instance.js';
const props = defineProps<{
showLoginPopup?: boolean;

View File

@@ -11,11 +11,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<Transition :name="defaultStore.state.animation ? 'fade' : ''" mode="out-in">
<div v-if="note">
<div v-if="showNext" class="_margin">
<MkNotes class="" :pagination="nextPagination" :noGap="true"/>
<MkNotes class="" :pagination="nextPagination" :noGap="true" :disableAutoLoad="true"/>
</div>
<div class="_margin">
<MkButton v-if="!showNext && hasNext" :class="$style.loadNext" @click="showNext = true"><i class="ti ti-chevron-up"></i></MkButton>
<MkButton v-if="!showNext" :class="$style.loadNext" @click="showNext = true"><i class="ti ti-chevron-up"></i></MkButton>
<div class="_margin _gaps_s">
<MkRemoteCaution v-if="note.user.host != null" :href="note.url ?? note.uri"/>
<MkNoteDetailed :key="note.id" v-model:note="note" :class="$style.note"/>
@@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkA>
</div>
</div>
<MkButton v-if="!showPrev && hasPrev" :class="$style.loadPrev" @click="showPrev = true"><i class="ti ti-chevron-down"></i></MkButton>
<MkButton v-if="!showPrev" :class="$style.loadPrev" @click="showPrev = true"><i class="ti ti-chevron-down"></i></MkButton>
</div>
<div v-if="showPrev" class="_margin">
@@ -45,26 +45,24 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { computed, watch } from 'vue';
import * as misskey from 'misskey-js';
import * as Misskey from 'misskey-js';
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
import MkNotes from '@/components/MkNotes.vue';
import MkRemoteCaution from '@/components/MkRemoteCaution.vue';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import { dateString } from '@/filters/date';
import * as os from '@/os.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { i18n } from '@/i18n.js';
import { dateString } from '@/filters/date.js';
import MkClipPreview from '@/components/MkClipPreview.vue';
import { defaultStore } from '@/store';
import { defaultStore } from '@/store.js';
const props = defineProps<{
noteId: string;
}>();
let note = $ref<null | misskey.entities.Note>();
let note = $ref<null | Misskey.entities.Note>();
let clips = $ref();
let hasPrev = $ref(false);
let hasNext = $ref(false);
let showPrev = $ref(false);
let showNext = $ref(false);
let error = $ref();
@@ -89,8 +87,6 @@ const nextPagination = {
};
function fetchNote() {
hasPrev = false;
hasNext = false;
showPrev = false;
showNext = false;
note = null;
@@ -98,25 +94,14 @@ function fetchNote() {
noteId: props.noteId,
}).then(res => {
note = res;
Promise.all([
// 古いートは被クリップ数をカウントしていないので、2023-10-01以前のものは強制的にnotes/clipsを叩く
if (note.clippedCount > 0 || new Date(note.createdAt).getTime() < new Date('2023-10-01').getTime()) {
os.api('notes/clips', {
noteId: note.id,
}),
os.api('users/notes', {
userId: note.userId,
untilId: note.id,
limit: 1,
}),
os.api('users/notes', {
userId: note.userId,
sinceId: note.id,
limit: 1,
}),
]).then(([_clips, prev, next]) => {
clips = _clips;
hasPrev = prev.length !== 0;
hasNext = next.length !== 0;
});
}).then((_clips) => {
clips = _clips;
});
}
}).catch(err => {
error = err;
});

View File

@@ -24,9 +24,9 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed } from 'vue';
import XNotifications from '@/components/MkNotifications.vue';
import MkNotes from '@/components/MkNotes.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { notificationTypes } from '@/const';
let tab = $ref('all');

View File

@@ -0,0 +1,72 @@
<!--
SPDX-FileCopyrightText: syuilo and other misskey contributors
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkStickyContainer>
<template #header><MkPageHeader/></template>
<MkSpacer :contentMax="800">
<div v-if="$i">
<div v-if="permissions.length > 0">
<p v-if="name">{{ i18n.t('_auth.permission', { name }) }}</p>
<p v-else>{{ i18n.ts._auth.permissionAsk }}</p>
<ul>
<li v-for="p in permissions" :key="p">{{ i18n.t(`_permissions.${p}`) }}</li>
</ul>
</div>
<div v-if="name">{{ i18n.t('_auth.shareAccess', { name }) }}</div>
<div v-else>{{ i18n.ts._auth.shareAccessAsk }}</div>
<form :class="$style.buttons" action="/oauth/decision" accept-charset="utf-8" method="post">
<input name="login_token" type="hidden" :value="$i.token"/>
<input name="transaction_id" type="hidden" :value="transactionIdMeta?.content"/>
<MkButton inline name="cancel" value="cancel">{{ i18n.ts.cancel }}</MkButton>
<MkButton inline primary>{{ i18n.ts.accept }}</MkButton>
</form>
</div>
<div v-else>
<p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p>
<MkSignin @login="onLogin"/>
</div>
</MkSpacer>
</MkStickyContainer>
</template>
<script lang="ts" setup>
import MkSignin from '@/components/MkSignin.vue';
import MkButton from '@/components/MkButton.vue';
import { $i, login } from '@/account.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
const transactionIdMeta = document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:transaction-id"]');
if (transactionIdMeta) {
transactionIdMeta.remove();
}
const name = document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-name"]')?.content;
const permissions = document.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:scope"]')?.content.split(' ') ?? [];
function onLogin(res): void {
login(res.i);
}
definePageMetadata({
title: 'OAuth',
icon: 'ti ti-apps',
});
</script>
<style lang="scss" module>
.buttons {
margin-top: 16px;
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.loginMessage {
text-align: center;
margin: 8px 0 24px;
}
</style>

View File

@@ -24,8 +24,8 @@ SPDX-License-Identifier: AGPL-3.0-only
import { onMounted } from 'vue';
import XContainer from '../page-editor.container.vue';
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
modelValue: any

View File

@@ -29,8 +29,8 @@ import MkInput from '@/components/MkInput.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkNote from '@/components/MkNote.vue';
import MkNoteDetailed from '@/components/MkNoteDetailed.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
const props = defineProps<{
modelValue: any

View File

@@ -25,9 +25,9 @@ SPDX-License-Identifier: AGPL-3.0-only
import { defineAsyncComponent, inject, onMounted, watch } from 'vue';
import { v4 as uuid } from 'uuid';
import XContainer from '../page-editor.container.vue';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { deepClone } from '@/scripts/clone';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { deepClone } from '@/scripts/clone.js';
import MkButton from '@/components/MkButton.vue';
const XBlocks = defineAsyncComponent(() => import('../page-editor.blocks.vue'));

View File

@@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
/* eslint-disable vue/no-mutating-props */
import { watch } from 'vue';
import XContainer from '../page-editor.container.vue';
import { i18n } from '@/i18n';
import { i18n } from '@/i18n.js';
const props = defineProps<{
modelValue: any

View File

@@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref } from 'vue';
import { i18n } from '@/i18n';
import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{
expanded?: boolean;

View File

@@ -68,13 +68,13 @@ import MkButton from '@/components/MkButton.vue';
import MkSelect from '@/components/MkSelect.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkInput from '@/components/MkInput.vue';
import { url } from '@/config';
import * as os from '@/os';
import { selectFile } from '@/scripts/select-file';
import { mainRouter } from '@/router';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import { $i } from '@/account';
import { url } from '@/config.js';
import * as os from '@/os.js';
import { selectFile } from '@/scripts/select-file.js';
import { mainRouter } from '@/router.js';
import { i18n } from '@/i18n.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { $i } from '@/account.js';
const props = defineProps<{
initPageId?: string;

Some files were not shown because too many files have changed in this diff Show More