mirror of
https://github.com/MisskeyIO/misskey
synced 2024-11-23 22:56:49 +09:00
Merge pull request MisskeyIO#761 from update-host
This commit is contained in:
commit
e4ec4b28dd
8
locales/index.d.ts
vendored
8
locales/index.d.ts
vendored
@ -580,6 +580,14 @@ export interface Locale extends ILocale {
|
||||
* リノートのミュートを解除
|
||||
*/
|
||||
"renoteUnmute": string;
|
||||
/**
|
||||
* リアクションのミュート
|
||||
*/
|
||||
"mutedReactions": string;
|
||||
/**
|
||||
* リモートの絵文字をミュート
|
||||
*/
|
||||
"remoteCustomEmojiMuted": string;
|
||||
/**
|
||||
* ブロック
|
||||
*/
|
||||
|
@ -141,6 +141,8 @@ mute: "ミュート"
|
||||
unmute: "ミュート解除"
|
||||
renoteMute: "リノートをミュート"
|
||||
renoteUnmute: "リノートのミュートを解除"
|
||||
mutedReactions: "リアクションのミュート"
|
||||
remoteCustomEmojiMuted: "リモートの絵文字をミュート"
|
||||
block: "ブロック"
|
||||
unblock: "ブロック解除"
|
||||
suspend: "凍結"
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"version": "2024.5.0-host.3a",
|
||||
"version": "2024.5.0-host.3b",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -64,11 +64,12 @@ export class JWTIdentifyProviderService {
|
||||
|
||||
fastify.all<{
|
||||
Params: { serviceId: string };
|
||||
Querystring?: { serviceurl?: string, return_to?: string };
|
||||
Body?: { serviceurl?: string, return_to?: string };
|
||||
Querystring?: { serviceurl?: string, return_to?: string, prompt?: string };
|
||||
Body?: { serviceurl?: string, return_to?: string, prompt?: string };
|
||||
}>('/:serviceId', async (request, reply) => {
|
||||
const serviceId = request.params.serviceId;
|
||||
const returnTo = request.query?.return_to ?? request.query?.serviceurl ?? request.body?.return_to ?? request.body?.serviceurl;
|
||||
const prompt = request.query?.prompt ?? request.body?.prompt ?? 'consent';
|
||||
|
||||
const ssoServiceProvider = await this.singleSignOnServiceProviderRepository.findOneBy({ id: serviceId, type: 'jwt' });
|
||||
if (!ssoServiceProvider) {
|
||||
@ -101,6 +102,7 @@ export class JWTIdentifyProviderService {
|
||||
transactionId: transactionId,
|
||||
serviceName: ssoServiceProvider.name ?? ssoServiceProvider.issuer,
|
||||
kind: 'jwt',
|
||||
prompt: prompt,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -201,13 +201,14 @@ export class SAMLIdentifyProviderService {
|
||||
|
||||
fastify.all<{
|
||||
Params: { serviceId: string };
|
||||
Querystring?: { SAMLRequest?: string; RelayState?: string };
|
||||
Body?: { SAMLRequest?: string; RelayState?: string };
|
||||
Querystring?: { SAMLRequest?: string; RelayState?: string, prompt?: string };
|
||||
Body?: { SAMLRequest?: string; RelayState?: string, prompt?: string };
|
||||
}>('/:serviceId', async (request, reply) => {
|
||||
const serviceId = request.params.serviceId;
|
||||
const binding = request.query?.SAMLRequest ? 'redirect' : 'post';
|
||||
const samlRequest = request.query?.SAMLRequest ?? request.body?.SAMLRequest;
|
||||
const relayState = request.query?.RelayState ?? request.body?.RelayState;
|
||||
const prompt = request.query?.prompt ?? request.body?.prompt ?? 'consent';
|
||||
|
||||
const ssoServiceProvider = await this.singleSignOnServiceProviderRepository.findOneBy({ id: serviceId, type: 'saml', privateKey: Not(IsNull()) });
|
||||
if (!ssoServiceProvider) {
|
||||
@ -268,6 +269,7 @@ export class SAMLIdentifyProviderService {
|
||||
transactionId: transactionId,
|
||||
serviceName: ssoServiceProvider.name ?? ssoServiceProvider.issuer,
|
||||
kind: 'saml',
|
||||
prompt: prompt,
|
||||
});
|
||||
} catch (err) {
|
||||
this.#logger.error('Failed to parse SAML request', { error: err });
|
||||
|
@ -4,3 +4,4 @@ block meta
|
||||
meta(name='misskey:sso:transaction-id' content=transactionId)
|
||||
meta(name='misskey:sso:service-name' content=serviceName)
|
||||
meta(name='misskey:sso:kind' content=kind)
|
||||
meta(name='misskey:sso:prompt' content=prompt)
|
||||
|
@ -29,15 +29,29 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
:max-height="maxHeight"
|
||||
@chosen="chosen"
|
||||
/>
|
||||
<div v-if="manualReactionInput" :class="$style.remoteReactionInputWrapper">
|
||||
<span>{{ i18n.ts.remoteCustomEmojiMuted }}</span>
|
||||
<MkInput v-model="remoteReactionName" placeholder=":emojiname@host:" autocapitalize="off"/>
|
||||
<MkButton :disabled="!(remoteReactionName && remoteReactionName[0] === ':')" @click="chosen(remoteReactionName)">
|
||||
{{ i18n.ts.add }}
|
||||
</MkButton>
|
||||
<div :class="$style.emojiContainer">
|
||||
<MkCustomEmoji v-if="remoteReactionName && remoteReactionName[0] === ':' " :class="$style.emoji" :name="remoteReactionName" :normal="true"/>
|
||||
</div>
|
||||
</div>
|
||||
</MkModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { shallowRef } from 'vue';
|
||||
import { shallowRef, ref } from 'vue';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import MkModal from '@/components/MkModal.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import MkCustomEmoji from '@/components/global/MkCustomEmoji.vue';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
manualShowing?: boolean | null;
|
||||
@ -47,12 +61,14 @@ const props = withDefaults(defineProps<{
|
||||
asReactionPicker?: boolean;
|
||||
targetNote?: Misskey.entities.Note;
|
||||
choseAndClose?: boolean;
|
||||
manualReactionInput?: boolean;
|
||||
}>(), {
|
||||
manualShowing: null,
|
||||
showPinned: true,
|
||||
pinnedEmojis: undefined,
|
||||
asReactionPicker: false,
|
||||
choseAndClose: true,
|
||||
manualReactionInput: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -64,6 +80,8 @@ const emit = defineEmits<{
|
||||
const modal = shallowRef<InstanceType<typeof MkModal>>();
|
||||
const picker = shallowRef<InstanceType<typeof MkEmojiPicker>>();
|
||||
|
||||
const remoteReactionName = ref('');
|
||||
|
||||
function chosen(emoji: string) {
|
||||
emit('done', emoji);
|
||||
if (props.choseAndClose) {
|
||||
@ -88,4 +106,16 @@ function opening() {
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.remoteReactionInputWrapper {
|
||||
margin-top: var(--margin);
|
||||
padding: 16px;
|
||||
border-radius: var(--radius);
|
||||
background: var(--popup);
|
||||
}
|
||||
|
||||
.emojiContainer {
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
}
|
||||
</style>
|
||||
|
@ -22,6 +22,7 @@ import * as Misskey from 'misskey-js';
|
||||
import { inject, watch, ref } from 'vue';
|
||||
import XReaction from '@/components/MkReactionsViewer.reaction.vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { $i } from '@/account.js';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
note: Misskey.entities.Note;
|
||||
@ -45,6 +46,13 @@ if (props.note.myReaction && !Object.keys(reactions.value).includes(props.note.m
|
||||
reactions.value[props.note.myReaction] = props.note.reactions[props.note.myReaction];
|
||||
}
|
||||
|
||||
function shouldDisplayReaction([reaction]: [string, number]): boolean {
|
||||
if (!$i) return true; // 非ログイン状態なら全部のリアクションを見れるように
|
||||
if (reaction === props.note.myReaction) return true; // 自分がつけたリアクションなら表示する
|
||||
if (!defaultStore.state.mutedReactions.includes(reaction.replace('@.', ''))) return true; // ローカルの絵文字には @. というsuffixがつくのでそれを消してから比較してあげる
|
||||
return false;
|
||||
}
|
||||
|
||||
function onMockToggleReaction(emoji: string, count: number) {
|
||||
if (!mock) return;
|
||||
|
||||
@ -80,7 +88,7 @@ watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumbe
|
||||
newReactions.push([props.note.myReaction, newSource[props.note.myReaction]]);
|
||||
}
|
||||
|
||||
reactions.value = newReactions;
|
||||
reactions.value = newReactions.filter(shouldDisplayReaction);
|
||||
}, { immediate: true, deep: true });
|
||||
</script>
|
||||
|
||||
@ -104,6 +112,7 @@ watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumbe
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
margin: 4px -2px 0 -2px;
|
||||
max-width: 100%;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<span v-if="errored">:{{ customEmojiName }}:</span>
|
||||
<img v-if="errored" src="/client-assets/dummy.png" :alt="alt" :title="alt" decoding="async" :class="[$style.root, { [$style.normal]: normal, [$style.noStyle]: noStyle }]"/>
|
||||
<img
|
||||
v-else
|
||||
:class="[$style.root, { [$style.normal]: normal, [$style.noStyle]: noStyle }]"
|
||||
@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, ref } from 'vue';
|
||||
import { computed, inject, ref, watch } from 'vue';
|
||||
import { getProxiedImageUrl, getStaticImageUrl } from '@/scripts/media-proxy.js';
|
||||
import { defaultStore } from '@/store.js';
|
||||
import { customEmojisMap } from '@/custom-emojis.js';
|
||||
@ -73,6 +73,10 @@ const url = computed(() => {
|
||||
: proxied;
|
||||
});
|
||||
|
||||
watch(url, (newValue) => {
|
||||
errored.value = (newValue === undefined);
|
||||
});
|
||||
|
||||
const alt = computed(() => `:${customEmojiName.value}:`);
|
||||
const errored = ref(url.value == null);
|
||||
|
||||
|
@ -12,6 +12,23 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<XWordMute :muted="$i.mutedWords" @save="saveMutedWords"/>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-message-off"></i></template>
|
||||
<template #label>{{ i18n.ts.mutedReactions }}</template>
|
||||
|
||||
<div class="_gaps">
|
||||
<div v-panel style="border-radius: var(--radius); padding: var(--margin);">
|
||||
<button v-for="emoji in mutedReactions" class="_button" :class="$style.emojisItem" @click="removeReaction(emoji, $event)">
|
||||
<MkCustomEmoji v-if="emoji && emoji[0] === ':'" :name="emoji"/>
|
||||
<MkEmoji v-else :emoji="emoji ? emoji : 'null'"/>
|
||||
</button>
|
||||
<button class="_button" @click="chooseReaction">
|
||||
<i class="ti ti-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #icon><i class="ti ti-planet-off"></i></template>
|
||||
<template #label>{{ i18n.ts.instanceMute }}</template>
|
||||
@ -119,7 +136,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { ref, computed, watch, Ref } from 'vue';
|
||||
import XInstanceMute from './mute-block.instance-mute.vue';
|
||||
import XWordMute from './mute-block.word-mute.vue';
|
||||
import MkPagination from '@/components/MkPagination.vue';
|
||||
@ -132,6 +149,9 @@ import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { infoImageUrl } from '@/instance.js';
|
||||
import { signinRequired } from '@/account.js';
|
||||
import MkFolder from '@/components/MkFolder.vue';
|
||||
import MkCustomEmoji from '@/components/global/MkCustomEmoji.vue';
|
||||
import MkEmoji from '@/components/global/MkEmoji.vue';
|
||||
import { defaultStore } from '@/store.js';
|
||||
|
||||
const $i = signinRequired();
|
||||
|
||||
@ -154,6 +174,38 @@ const expandedRenoteMuteItems = ref([]);
|
||||
const expandedMuteItems = ref([]);
|
||||
const expandedBlockItems = ref([]);
|
||||
|
||||
const mutedReactions = ref<string[]>(defaultStore.state.mutedReactions);
|
||||
|
||||
watch(mutedReactions, () => {
|
||||
defaultStore.set('mutedReactions', mutedReactions.value);
|
||||
}, {
|
||||
deep: true,
|
||||
});
|
||||
|
||||
const chooseReaction = (ev: MouseEvent) => pickEmoji(mutedReactions, ev);
|
||||
const removeReaction = (reaction: string, ev: MouseEvent) => remove(mutedReactions, reaction, ev);
|
||||
|
||||
function remove(itemsRef: Ref<string[]>, reaction: string, ev: MouseEvent) {
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.remove,
|
||||
action: () => {
|
||||
itemsRef.value = itemsRef.value.filter(x => x !== reaction);
|
||||
},
|
||||
}], ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
async function pickEmoji(itemsRef: Ref<string[]>, ev: MouseEvent) {
|
||||
os.pickEmoji(ev.currentTarget ?? ev.target, {
|
||||
showPinned: false,
|
||||
manualReactionInput: true,
|
||||
}).then(it => {
|
||||
const emoji = it;
|
||||
if (!itemsRef.value.includes(emoji)) {
|
||||
itemsRef.value.push(emoji);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function unrenoteMute(user, ev) {
|
||||
os.popupMenu([{
|
||||
text: i18n.ts.renoteUnmute,
|
||||
@ -263,4 +315,9 @@ definePageMetadata(() => ({
|
||||
transform: rotateX(180deg);
|
||||
}
|
||||
}
|
||||
|
||||
.emojisItem{
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
}
|
||||
</style>
|
||||
|
@ -120,6 +120,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
||||
'sound_notification',
|
||||
'sound_antenna',
|
||||
'sound_channel',
|
||||
'mutedReactions',
|
||||
];
|
||||
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
||||
'lightTheme',
|
||||
|
@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, nextTick } from 'vue';
|
||||
import { ref, nextTick, onMounted } from 'vue';
|
||||
import MkSignin from '@/components/MkSignin.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import { $i, login } from '@/account.js';
|
||||
@ -47,6 +47,7 @@ if (transactionIdMeta) {
|
||||
}
|
||||
const name = document.querySelector<HTMLMetaElement>('meta[name="misskey:sso:service-name"]')?.content;
|
||||
const kind = document.querySelector<HTMLMetaElement>('meta[name="misskey:sso:kind"]')?.content;
|
||||
const prompt = document.querySelector<HTMLMetaElement>('meta[name="misskey:sso:prompt"]')?.content;
|
||||
|
||||
const loading = ref(false);
|
||||
const postBindingForm = ref<HTMLFormElement | null>(null);
|
||||
@ -90,6 +91,12 @@ async function authorize(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if ($i && prompt === 'none') {
|
||||
onAccept();
|
||||
}
|
||||
});
|
||||
|
||||
definePageMetadata(() => ({
|
||||
title: 'Single Sign-On',
|
||||
icon: 'ti ti-apps',
|
||||
|
@ -507,6 +507,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||
where: 'device',
|
||||
default: { type: 'syuilo/bubble2', volume: 1 } as SoundStore,
|
||||
},
|
||||
mutedReactions: {
|
||||
where: 'account',
|
||||
default: [] as string[],
|
||||
},
|
||||
}));
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "module",
|
||||
"name": "misskey-js",
|
||||
"version": "2024.5.0-host.3a",
|
||||
"version": "2024.5.0-host.3b",
|
||||
"description": "Misskey SDK for JavaScript",
|
||||
"types": "./built/dts/index.d.ts",
|
||||
"exports": {
|
||||
|
Loading…
Reference in New Issue
Block a user