Merge branch 'develop' into feat-tabler-subset

This commit is contained in:
かっこかり 2025-01-26 17:45:09 +09:00 committed by GitHub
commit 8252036cff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 209 additions and 2 deletions

View File

@ -23,6 +23,7 @@
(Based on https://github.com/Otaku-Social/maniakey/pull/14)
- Enhance: AiScriptの拡張API関数において引数の型チェックをより厳格に
- Enhance: クエリパラメータでuiを一時的に変更できるように #15240
- Enhance: リモート絵文字のインポート時に詳細を確認できるように #15336
- Enhance: UIのアイコンデータの読み込みを軽量化
- Fix: 画面サイズが変わった際にナビゲーションバーが自動で折りたたまれない問題を修正
- Fix: サーバー情報メニューに区切り線が不足していたのを修正
@ -38,6 +39,7 @@
(Cherry-picked from https://github.com/TeamNijimiss/misskey/commit/800359623e41a662551d774de15b0437b6849bb4)
- Fix: ノート作成画面でファイルの添付可能個数を超えてもノートボタンが押せていた問題を修正
- Fix: 「アカウントを管理」画面で、ユーザー情報の取得に失敗したアカウント(削除されたアカウントなど)が表示されない問題を修正
- Fix: MacOSでChrome系ブラウザを使用している場合に、Misskeyを閉じた際に他のタブのオーディオ機能と干渉する問題を修正
- Fix: 言語データのキャッシュ状況によっては、埋め込みウィジェットが正しく起動しない問題を修正
- Fix: 「削除して編集」でノートの引用を解除出来なかった問題を修正( #14476 )
- Fix: RSSウィジェットが正しく表示されない問題を修正
@ -58,6 +60,7 @@
- Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 )
- Fix: 起動前の疎通チェックが機能しなくなっていた問題を修正
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/737)
- Fix: ートの閲覧にログイン必須にしてもFeedでートが表示されてしまう問題を修正
- Fix: 絵文字の連合でライセンス欄を相互にやり取りするように ( #10859, #14109 )
- Fix: ロックダウンされた期間指定のートがStreaming経由でLTLに出現するのを修正 ( #15200 )
- Fix: disableClustering設定時の初期化ロジックを調整( #15223 )

4
locales/index.d.ts vendored
View File

@ -10635,6 +10635,10 @@ export interface Locale extends ILocale {
"logNothing": string;
};
"_remote": {
/**
*
*/
"selectionRowDetail": string;
/**
*
*/

View File

@ -2837,6 +2837,7 @@ _customEmojisManager:
failureLogNothing: "失敗ログはありません。"
logNothing: "ログはありません。"
_remote:
selectionRowDetail: "選択行の詳細"
importSelectionRows: "選択行をインポート"
importSelectionRangesRows: "選択範囲の行をインポート"
importEmojisButton: "チェックされた絵文字をインポート"

View File

@ -512,6 +512,7 @@ export class ClientServerService {
usernameLower: username.toLowerCase(),
host: host ?? IsNull(),
isSuspended: false,
requireSigninToViewContents: false,
});
return user && await this.feedService.packFeed(user);

View File

@ -0,0 +1,132 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<MkWindow
ref="windowEl"
:initialWidth="400"
:initialHeight="500"
:canResize="true"
@close="windowEl?.close()"
@closed="emit('closed')"
>
<template #header>:{{ name }}:</template>
<div style="display: flex; flex-direction: column; min-height: 100%;">
<MkSpacer :marginMin="20" :marginMax="28" style="flex-grow: 1;">
<div class="_gaps_m">
<div v-if="imgUrl != null" :class="$style.imgs">
<div style="background: #000;" :class="$style.imgContainer">
<img :src="imgUrl" :class="$style.img" :alt="name"/>
</div>
<div style="background: #222;" :class="$style.imgContainer">
<img :src="imgUrl" :class="$style.img" :alt="name"/>
</div>
<div style="background: #ddd;" :class="$style.imgContainer">
<img :src="imgUrl" :class="$style.img" :alt="name"/>
</div>
<div style="background: #fff;" :class="$style.imgContainer">
<img :src="imgUrl" :class="$style.img" :alt="name"/>
</div>
</div>
<MkKeyValue>
<template #key>{{ i18n.ts.id }}</template>
<template #value>{{ name }}</template>
</MkKeyValue>
<MkKeyValue>
<template #key>{{ i18n.ts.host }}</template>
<template #value>{{ host }}</template>
</MkKeyValue>
<MkKeyValue>
<template #key>{{ i18n.ts.license }}</template>
<template #value>{{ license }}</template>
</MkKeyValue>
</div>
</MkSpacer>
<div :class="$style.footer">
<MkButton primary rounded style="margin: 0 auto;" @click="done">
<i class="ti ti-plus"></i> {{ i18n.ts.import }}
</MkButton>
</div>
</div>
</MkWindow>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import MkKeyValue from '@/components/MkKeyValue.vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkTextarea from '@/components/MkTextarea.vue';
import MkWindow from '@/components/MkWindow.vue';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
const props = defineProps<{
emoji: {
id: string,
name: string,
host: string,
license: string | null,
url: string
},
}>();
const emit = defineEmits<{
//
(ev: 'done'): void,
(ev: 'closed'): void
}>();
const windowEl = ref<InstanceType<typeof MkWindow> | null>(null);
const name = computed(() => props.emoji.name);
const host = computed(() => props.emoji.host);
const license = computed(() => props.emoji.license);
const imgUrl = computed(() => props.emoji.url);
async function done() {
await os.apiWithDialog('admin/emoji/copy', {
emojiId: props.emoji.id,
});
emit('done');
windowEl.value?.close();
}
</script>
<style lang="scss" module>
.imgs {
display: flex;
gap: 8px;
flex-wrap: wrap;
justify-content: center;
}
.imgContainer {
padding: 8px;
border-radius: 6px;
}
.img {
display: block;
height: 64px;
width: 64px;
object-fit: contain;
}
.footer {
position: sticky;
z-index: 10000;
bottom: 0;
left: 0;
padding: 12px;
border-top: solid 0.5px var(--MI_THEME-divider);
background: var(--MI_THEME-acrylicBg);
-webkit-backdrop-filter: var(--MI-blur, blur(15px));
backdrop-filter: var(--MI-blur, blur(15px));
}
</style>

View File

@ -34,6 +34,16 @@ SPDX-License-Identifier: AGPL-3.0-only
>
<template #label>host</template>
</MkInput>
<MkInput
v-model="queryLicense"
type="search"
autocapitalize="off"
:class="[$style.col3, $style.row1]"
@enter="onSearchRequest"
>
<template #label>license</template>
</MkInput>
<MkInput
v-model="queryUri"
type="search"
@ -115,6 +125,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script setup lang="ts">
import { computed, onMounted, ref, useCssModule } from 'vue';
import * as Misskey from 'misskey-js';
import MkRemoteEmojiEditDialog from '@/components/MkRemoteEmojiEditDialog.vue';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { i18n } from '@/i18n.js';
import MkButton from '@/components/MkButton.vue';
@ -135,7 +146,7 @@ import { deviceKind } from '@/scripts/device-kind.js';
import MkPagingButtons from '@/components/MkPagingButtons.vue';
import MkSortOrderEditor from '@/components/MkSortOrderEditor.vue';
import { SortOrder } from '@/components/MkSortOrderEditor.define.js';
import { useLoading } from "@/components/hook/useLoading.js";
import { useLoading } from '@/components/hook/useLoading.js';
type GridItem = {
checked: boolean;
@ -178,12 +189,37 @@ function setupGrid(): GridSetting {
{ bindTo: 'url', icon: 'ti-icons', type: 'image', editable: false, width: 'auto' },
{ bindTo: 'name', title: 'name', type: 'text', editable: false, width: 'auto' },
{ bindTo: 'host', title: 'host', type: 'text', editable: false, width: 'auto' },
{ bindTo: 'license', title: 'license', type: 'text', editable: false, width: 200 },
{ bindTo: 'uri', title: 'uri', type: 'text', editable: false, width: 'auto' },
{ bindTo: 'publicUrl', title: 'publicUrl', type: 'text', editable: false, width: 'auto' },
],
cells: {
contextMenuFactory: (col, row, value, context) => {
return [
{
type: 'button',
text: i18n.ts._customEmojisManager._remote.selectionRowDetail,
icon: 'ti ti-info-circle',
action: async () => {
const target = customEmojis.value[row.index];
const { dispose } = os.popup(MkRemoteEmojiEditDialog, {
emoji: {
id: target.id,
name: target.name,
host: target.host!,
license: target.license,
url: target.publicUrl,
},
}, {
done: () => {
dispose();
},
closed: () => {
dispose();
},
});
},
},
{
type: 'button',
text: i18n.ts._customEmojisManager._remote.importSelectionRangesRows,
@ -207,6 +243,7 @@ const currentPage = ref<number>(0);
const queryName = ref<string | null>(null);
const queryHost = ref<string | null>(null);
const queryLicense = ref<string | null>(null);
const queryUri = ref<string | null>(null);
const queryPublicUrl = ref<string | null>(null);
const previousQuery = ref<string | undefined>(undefined);
@ -229,6 +266,7 @@ async function onSearchRequest() {
function onQueryResetButtonClicked() {
queryName.value = null;
queryHost.value = null;
queryLicense.value = null;
queryUri.value = null;
queryPublicUrl.value = null;
}
@ -306,6 +344,7 @@ async function refreshCustomEmojis() {
const query: Misskey.entities.V2AdminEmojiListRequest['query'] = {
name: emptyStrToUndefined(queryName.value),
host: emptyStrToUndefined(queryHost.value),
license: emptyStrToUndefined(queryLicense.value),
uri: emptyStrToUndefined(queryUri.value),
publicUrl: emptyStrToUndefined(queryPublicUrl.value),
hostType: 'remote',
@ -330,6 +369,7 @@ async function refreshCustomEmojis() {
id: it.id,
url: it.publicUrl,
name: it.name,
license: it.license,
host: it.host!,
}));
}
@ -356,6 +396,10 @@ onMounted(async () => {
grid-column: 2 / 3;
}
.col3 {
grid-column: 3 / 4;
}
.root {
padding: 16px;
}
@ -366,7 +410,7 @@ onMounted(async () => {
.searchArea {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
gap: 16px;
}

View File

@ -78,6 +78,7 @@ import { computed, defineAsyncComponent, ref, shallowRef } from 'vue';
import MkButton from '@/components/MkButton.vue';
import MkInput from '@/components/MkInput.vue';
import MkPagination from '@/components/MkPagination.vue';
import MkRemoteEmojiEditDialog from '@/components/MkRemoteEmojiEditDialog.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import FormSplit from '@/components/form/split.vue';
import { selectFile } from '@/scripts/select-file.js';
@ -159,6 +160,19 @@ const edit = (emoji) => {
});
};
const detailRemoteEmoji = (emoji) => {
const { dispose } = os.popup(MkRemoteEmojiEditDialog, {
emoji: emoji,
}, {
done: () => {
dispose();
},
closed: () => {
dispose();
},
});
};
const importEmoji = (emoji) => {
os.apiWithDialog('admin/emoji/copy', {
emojiId: emoji.id,
@ -169,6 +183,10 @@ const remoteMenu = (emoji, ev: MouseEvent) => {
os.popupMenu([{
type: 'label',
text: ':' + emoji.name + ':',
}, {
text: i18n.ts.details,
icon: 'ti ti-info-circle',
action: () => { detailRemoteEmoji(emoji); },
}, {
text: i18n.ts.import,
icon: 'ti ti-plus',

View File

@ -93,6 +93,10 @@ export async function loadAudio(url: string, options?: { useCache?: boolean; })
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (ctx == null) {
ctx = new AudioContext();
window.addEventListener('beforeunload', () => {
ctx.close();
});
}
if (options?.useCache ?? true) {
if (cache.has(url)) {