diff options
| author | Hazelnoot <acomputerdog@gmail.com> | 2025-03-02 18:56:44 +0000 |
|---|---|---|
| committer | Hazelnoot <acomputerdog@gmail.com> | 2025-03-02 18:56:44 +0000 |
| commit | 141bce2be7a5b8756d58e2d4e92d1f6180629da4 (patch) | |
| tree | c73d3940938e4fd8cc515377f9334c4a48679c7b /packages/frontend/src/components | |
| parent | merge: Remove assertActivityMatchesUrls in favor of three-way same-authority ... (diff) | |
| parent | remove `fileId` from `importCustomEmojis` log (diff) | |
| download | sharkey-141bce2be7a5b8756d58e2d4e92d1f6180629da4.tar.gz sharkey-141bce2be7a5b8756d58e2d4e92d1f6180629da4.tar.bz2 sharkey-141bce2be7a5b8756d58e2d4e92d1f6180629da4.zip | |
merge: Add/fix moderation logs for many endpoints (resolves #911 and #969) (!925)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/925
Closes #911 and #969
Approved-by: dakkar <dakkar@thenautilus.net>
Approved-by: Marie <github@yuugi.dev>
Diffstat (limited to 'packages/frontend/src/components')
| -rw-r--r-- | packages/frontend/src/components/DynamicNote.vue | 49 | ||||
| -rw-r--r-- | packages/frontend/src/components/SkFetchNote.vue | 69 | ||||
| -rw-r--r-- | packages/frontend/src/components/global/MkLazy.vue | 10 |
3 files changed, 128 insertions, 0 deletions
diff --git a/packages/frontend/src/components/DynamicNote.vue b/packages/frontend/src/components/DynamicNote.vue new file mode 100644 index 0000000000..6703099591 --- /dev/null +++ b/packages/frontend/src/components/DynamicNote.vue @@ -0,0 +1,49 @@ +<!-- +SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<XNote + ref="rootEl" + :note="note" + :pinned="pinned" + :mock="mock" + :withHardMute="withHardMute" + @reaction="emoji => emit('reaction', emoji)" + @removeReaction="emoji => emit('removeReaction', emoji)" +/> +</template> + +<script setup lang="ts"> +import * as Misskey from 'misskey-js'; +import { computed, defineAsyncComponent, shallowRef } from 'vue'; +import type { ComponentExposed } from 'vue-component-type-helpers'; +import type MkNote from '@/components/MkNote.vue'; +import type SkNote from '@/components/SkNote.vue'; +import { defaultStore } from '@/store'; + +const XNote = computed(() => + defineAsyncComponent(() => + defaultStore.reactiveState.noteDesign.value === 'misskey' + ? import('@/components/MkNote.vue') + : import('@/components/SkNote.vue'), + ), +); + +const rootEl = shallowRef<ComponentExposed<typeof MkNote | typeof SkNote>>(); + +defineExpose({ rootEl }); + +defineProps<{ + note: Misskey.entities.Note; + pinned?: boolean; + mock?: boolean; + withHardMute?: boolean; +}>(); + +const emit = defineEmits<{ + (ev: 'reaction', emoji: string): void; + (ev: 'removeReaction', emoji: string): void; +}>(); +</script> diff --git a/packages/frontend/src/components/SkFetchNote.vue b/packages/frontend/src/components/SkFetchNote.vue new file mode 100644 index 0000000000..ab702c28f8 --- /dev/null +++ b/packages/frontend/src/components/SkFetchNote.vue @@ -0,0 +1,69 @@ +<!-- +SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<MkLazy @show="showing = true"> + <MkLoading v-if="state === 'loading'"/> + + <div v-if="state === 'error'">{{ i18n.ts.cannotLoadNote }}</div> + + <DynamicNote v-if="state === 'done' && note" :note="note"/> +</MkLazy> +</template> + +<script setup lang="ts"> +import { ref, watch } from 'vue'; +import * as Misskey from 'misskey-js'; +import { i18n } from '@/i18n.js'; +import { misskeyApi } from '@/scripts/misskey-api'; +import DynamicNote from '@/components/DynamicNote.vue'; + +const props = withDefaults(defineProps<{ + noteId: string, + lazy?: boolean, +}>(), { + lazy: true, +}); + +// Lazy-load, unless props.lazy is false. +// eslint-disable-next-line vue/no-setup-props-reactivity-loss +const showing = ref(!props.lazy); +const state = ref<'loading' | 'error' | 'done'>('loading'); +const note = ref<Misskey.entities.Note | null>(null); + +watch( + [ + () => props.noteId, + () => showing.value, + ], + async ([noteId, show]) => { + // Wait until the note is visible to avoid bombarding the API with requests. + if (!show) return; + + // Unload the old note + note.value = null; + state.value = 'loading'; + + // Fetch the new note + const newNote = await misskeyApi('notes/show', { noteId }).catch(() => null); + + // Check for race conditions (ex. the note changed again while the first request was still running) + if (noteId !== props.noteId) return; + + // Check for errors + if (!newNote) { + state.value = 'error'; + return; + } + + // Display the new note + note.value = newNote; + state.value = 'done'; + }, + { + immediate: true, + }, +); +</script> diff --git a/packages/frontend/src/components/global/MkLazy.vue b/packages/frontend/src/components/global/MkLazy.vue index f35932ae77..29908f303d 100644 --- a/packages/frontend/src/components/global/MkLazy.vue +++ b/packages/frontend/src/components/global/MkLazy.vue @@ -16,10 +16,20 @@ import { nextTick, onMounted, onActivated, onBeforeUnmount, ref, shallowRef } fr const rootEl = shallowRef<HTMLDivElement>(); const showing = ref(false); +const emit = defineEmits<{ + (ev: 'show'): void, +}>(); + const observer = new IntersectionObserver( (entries) => { if (entries.some((entry) => entry.isIntersecting)) { showing.value = true; + + // Disconnect to avoid observer soft-leaks + observer.disconnect(); + + // Notify containing element to trigger edge logic + emit('show'); } }, ); |