mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 15:34:13 +00:00 
			
		
		
		
	fixes from peer review
This commit is contained in:
		
							parent
							
								
									19204851a0
								
							
						
					
					
						commit
						ef7cde6bc6
					
				
					 7 changed files with 30 additions and 24 deletions
				
			
		| 
						 | 
					@ -1134,7 +1134,8 @@ export class NoteCreateService implements OnApplicationShutdown {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private async updateLatestNote(note: MiNote) {
 | 
						private async updateLatestNote(note: MiNote) {
 | 
				
			||||||
		// Ignore DMs
 | 
							// Ignore DMs.
 | 
				
			||||||
 | 
							// Followers-only posts are *included*, as this table is used to back the "following" feed.
 | 
				
			||||||
		if (note.visibility === 'specified') return;
 | 
							if (note.visibility === 'specified') return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Ignore pure renotes
 | 
							// Ignore pure renotes
 | 
				
			||||||
| 
						 | 
					@ -1143,7 +1144,7 @@ export class NoteCreateService implements OnApplicationShutdown {
 | 
				
			||||||
		// Make sure that this isn't an *older* post.
 | 
							// Make sure that this isn't an *older* post.
 | 
				
			||||||
		// We can get older posts through replies, lookups, etc.
 | 
							// We can get older posts through replies, lookups, etc.
 | 
				
			||||||
		const currentLatest = await this.latestNotesRepository.findOneBy({ userId: note.userId });
 | 
							const currentLatest = await this.latestNotesRepository.findOneBy({ userId: note.userId });
 | 
				
			||||||
		if (currentLatest != null && currentLatest.userId >= note.id) return;
 | 
							if (currentLatest != null && currentLatest.noteId >= note.id) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Record this as the latest note for the given user
 | 
							// Record this as the latest note for the given user
 | 
				
			||||||
		const latestNote = new LatestNote({
 | 
							const latestNote = new LatestNote({
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,6 +240,10 @@ export class NoteDeleteService {
 | 
				
			||||||
		// If it's a DM, then it can't possibly be the latest note so we can safely skip this.
 | 
							// If it's a DM, then it can't possibly be the latest note so we can safely skip this.
 | 
				
			||||||
		if (note.visibility === 'specified') return;
 | 
							if (note.visibility === 'specified') return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Check if the deleted note was possibly the latest for the user
 | 
				
			||||||
 | 
							const hasLatestNote = await this.latestNotesRepository.existsBy({ userId: note.userId });
 | 
				
			||||||
 | 
							if (hasLatestNote) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Find the newest remaining note for the user.
 | 
							// Find the newest remaining note for the user.
 | 
				
			||||||
		// We exclude DMs and pure renotes.
 | 
							// We exclude DMs and pure renotes.
 | 
				
			||||||
		const nextLatest = await this.notesRepository
 | 
							const nextLatest = await this.notesRepository
 | 
				
			||||||
| 
						 | 
					@ -269,12 +273,14 @@ export class NoteDeleteService {
 | 
				
			||||||
			noteId: nextLatest.id,
 | 
								noteId: nextLatest.id,
 | 
				
			||||||
		});
 | 
							});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// We use an upsert because this deleted note might not have been the newest.
 | 
							// When inserting the latest note, it's possible that another worker has "raced" the insert and already added a newer note.
 | 
				
			||||||
		// In that case, the latest note may already be populated for this user.
 | 
							// We must use orIgnore() to ensure that the query ignores conflicts, otherwise an exception may be thrown.
 | 
				
			||||||
		// We want postgres to do nothing instead of replacing the value or returning an error.
 | 
							await this.latestNotesRepository
 | 
				
			||||||
		await this.latestNotesRepository.upsert(latestNote, {
 | 
								.createQueryBuilder('latest')
 | 
				
			||||||
			conflictPaths: ['userId'],
 | 
								.insert()
 | 
				
			||||||
			skipUpdateIfNoValuesChanged: true,
 | 
								.into(LatestNote)
 | 
				
			||||||
		});
 | 
								.values(latestNote)
 | 
				
			||||||
 | 
								.orIgnore()
 | 
				
			||||||
 | 
								.execute();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
			</MkA>
 | 
								</MkA>
 | 
				
			||||||
		</header>
 | 
							</header>
 | 
				
			||||||
		<div>
 | 
							<div>
 | 
				
			||||||
			<Mfm :class="$style.text" :text="getNoteSummary(note)" :isBlock="false" :plain="true" :nowrap="false" :isNote="true" :author="note.user"/>
 | 
								<Mfm :class="$style.text" :text="getNoteSummary(note)" :isBlock="true" :plain="true" :nowrap="false" :isNote="true" nyaize="respect" :author="note.user"/>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,7 +70,7 @@ export const navbarItemDef = reactive({
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	following: {
 | 
						following: {
 | 
				
			||||||
		title: i18n.ts.following,
 | 
							title: i18n.ts.following,
 | 
				
			||||||
		icon: 'ti ti-user-check',
 | 
							icon: 'ph-user-check ph-bold ph-lg',
 | 
				
			||||||
		to: '/following-feed',
 | 
							to: '/following-feed',
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	lists: {
 | 
						lists: {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
					</MkPagination>
 | 
										</MkPagination>
 | 
				
			||||||
				</MkPullToRefresh>
 | 
									</MkPullToRefresh>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				<MkPullToRefresh v-if="isDesktop" :refresher="() => reloadUserNotes()">
 | 
									<MkPullToRefresh v-if="isWideViewport" :refresher="() => reloadUserNotes()">
 | 
				
			||||||
					<div v-if="selectedUser" :class="$style.userInfo">
 | 
										<div v-if="selectedUser" :class="$style.userInfo">
 | 
				
			||||||
						<MkUserInfo class="user" :user="selectedUser"/>
 | 
											<MkUserInfo class="user" :user="selectedUser"/>
 | 
				
			||||||
						<MkNotes :noGap="true" :pagination="userNotesPagination"/>
 | 
											<MkNotes :noGap="true" :pagination="userNotesPagination"/>
 | 
				
			||||||
| 
						 | 
					@ -62,7 +62,7 @@ import FollowingFeedEntry from '@/components/FollowingFeedEntry.vue';
 | 
				
			||||||
import MkNotes from '@/components/MkNotes.vue';
 | 
					import MkNotes from '@/components/MkNotes.vue';
 | 
				
			||||||
import MkUserInfo from '@/components/MkUserInfo.vue';
 | 
					import MkUserInfo from '@/components/MkUserInfo.vue';
 | 
				
			||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
 | 
					import { misskeyApi } from '@/scripts/misskey-api.js';
 | 
				
			||||||
import {useRouter} from "@/router/supplier.js";
 | 
					import { useRouter } from '@/router/supplier.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = withDefaults(defineProps<{
 | 
					const props = withDefaults(defineProps<{
 | 
				
			||||||
	initialTab?: FollowingFeedTab,
 | 
						initialTab?: FollowingFeedTab,
 | 
				
			||||||
| 
						 | 
					@ -79,17 +79,17 @@ const currentTab: Ref<FollowingFeedTab> = ref(props.initialTab);
 | 
				
			||||||
const mutualsOnly: Ref<boolean> = computed(() => currentTab.value === mutualsTab);
 | 
					const mutualsOnly: Ref<boolean> = computed(() => currentTab.value === mutualsTab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// We have to disable the per-user feed on small displays, and it must be done through JS instead of CSS.
 | 
					// We have to disable the per-user feed on small displays, and it must be done through JS instead of CSS.
 | 
				
			||||||
// Otherwise, the second column will resources in the background.
 | 
					// Otherwise, the second column will waste resources in the background.
 | 
				
			||||||
const desktopMediaQuery = window.matchMedia('(min-width: 750px)');
 | 
					const wideViewportQuery = window.matchMedia('(min-width: 750px)');
 | 
				
			||||||
const isDesktop: Ref<boolean> = ref(desktopMediaQuery.matches);
 | 
					const isWideViewport: Ref<boolean> = ref(wideViewportQuery.matches);
 | 
				
			||||||
desktopMediaQuery.addEventListener('change', () => isDesktop.value = desktopMediaQuery.matches);
 | 
					wideViewportQuery.addEventListener('change', () => isWideViewport.value = wideViewportQuery.matches);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const selectedUserError: Ref<string> = ref('');
 | 
					const selectedUserError: Ref<string> = ref('');
 | 
				
			||||||
const selectedUserId: Ref<string> = ref('');
 | 
					const selectedUserId: Ref<string> = ref('');
 | 
				
			||||||
const selectedUser: Ref<Misskey.entities.UserDetailed | null> = ref(null);
 | 
					const selectedUser: Ref<Misskey.entities.UserDetailed | null> = ref(null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function userSelected(user: Misskey.entities.UserLite): Promise<void> {
 | 
					async function userSelected(user: Misskey.entities.UserLite): Promise<void> {
 | 
				
			||||||
	if (isDesktop.value) {
 | 
						if (isWideViewport.value) {
 | 
				
			||||||
		await showUserNotes(user.id);
 | 
							await showUserNotes(user.id);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if (user.host) {
 | 
							if (user.host) {
 | 
				
			||||||
| 
						 | 
					@ -139,7 +139,7 @@ async function onListReady(): Promise<void> {
 | 
				
			||||||
		// This just gets the first user ID
 | 
							// This just gets the first user ID
 | 
				
			||||||
		const selectedNote: Misskey.entities.Note = latestNotesPaging.value.items.values().next().value;
 | 
							const selectedNote: Misskey.entities.Note = latestNotesPaging.value.items.values().next().value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Wait for 1 second to match the animation effects.
 | 
							// Wait for 1 second to match the animation effects in MkHorizontalSwipe, MkPullToRefresh, and MkPagination.
 | 
				
			||||||
		// Otherwise, the page appears to load "backwards".
 | 
							// Otherwise, the page appears to load "backwards".
 | 
				
			||||||
		await new Promise(resolve => setTimeout(resolve, 1000));
 | 
							await new Promise(resolve => setTimeout(resolve, 1000));
 | 
				
			||||||
		await showUserNotes(selectedNote.userId);
 | 
							await showUserNotes(selectedNote.userId);
 | 
				
			||||||
| 
						 | 
					@ -179,19 +179,19 @@ const headerActions: PageHeaderItem[] = [
 | 
				
			||||||
const headerTabs = computed(() => [
 | 
					const headerTabs = computed(() => [
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		key: followingTab,
 | 
							key: followingTab,
 | 
				
			||||||
		icon: 'ti ti-user-check',
 | 
							icon: 'ph-user-check ph-bold ph-lg',
 | 
				
			||||||
		title: i18n.ts.following,
 | 
							title: i18n.ts.following,
 | 
				
			||||||
	} satisfies Tab,
 | 
						} satisfies Tab,
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		key: mutualsTab,
 | 
							key: mutualsTab,
 | 
				
			||||||
		icon: 'ti ti-user-heart',
 | 
							icon: 'ph-user-switch ph-bold ph-lg',
 | 
				
			||||||
		title: i18n.ts.mutuals,
 | 
							title: i18n.ts.mutuals,
 | 
				
			||||||
	} satisfies Tab,
 | 
						} satisfies Tab,
 | 
				
			||||||
]);
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
definePageMetadata(() => ({
 | 
					definePageMetadata(() => ({
 | 
				
			||||||
	title: i18n.ts.following,
 | 
						title: i18n.ts.following,
 | 
				
			||||||
	icon: 'ti ti-user-check',
 | 
						icon: 'ph-user-check ph-bold ph-lg',
 | 
				
			||||||
}));
 | 
					}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -312,7 +312,7 @@ const headerTabs = computed(() => [...(defaultStore.reactiveState.pinnedUserList
 | 
				
			||||||
	icon: basicTimelineIconClass(tl),
 | 
						icon: basicTimelineIconClass(tl),
 | 
				
			||||||
	iconOnly: true,
 | 
						iconOnly: true,
 | 
				
			||||||
})), {
 | 
					})), {
 | 
				
			||||||
	icon: 'ti ti-user-check',
 | 
						icon: 'ph-user-check ph-bold ph-lg',
 | 
				
			||||||
	title: i18n.ts.following,
 | 
						title: i18n.ts.following,
 | 
				
			||||||
	iconOnly: true,
 | 
						iconOnly: true,
 | 
				
			||||||
	onClick: () => router.push('/following-feed'),
 | 
						onClick: () => router.push('/following-feed'),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -348,7 +348,6 @@ export function pluginReplaceIcons() {
 | 
				
			||||||
					'ti ti-user-circle': 'ph-user-circle ph-bold ph-lg',
 | 
										'ti ti-user-circle': 'ph-user-circle ph-bold ph-lg',
 | 
				
			||||||
					'ti ti-user-edit': 'ph-user-list ph-bold ph-lg',
 | 
										'ti ti-user-edit': 'ph-user-list ph-bold ph-lg',
 | 
				
			||||||
					'ti ti-user-exclamation': 'ph-warning-circle ph-bold ph-lg',
 | 
										'ti ti-user-exclamation': 'ph-warning-circle ph-bold ph-lg',
 | 
				
			||||||
					'ti ti-user-heart': 'ph-user-switch ph-bold ph-lg',
 | 
					 | 
				
			||||||
					'ti ti-user-off': 'ph-user-minus ph-bold ph-lg',
 | 
										'ti ti-user-off': 'ph-user-minus ph-bold ph-lg',
 | 
				
			||||||
					'ti ti-user-plus': 'ph-user-plus ph-bold ph-lg',
 | 
										'ti ti-user-plus': 'ph-user-plus ph-bold ph-lg',
 | 
				
			||||||
					'ti ti-user-search': 'ph-user-circle ph-bold ph-lg',
 | 
										'ti ti-user-search': 'ph-user-circle ph-bold ph-lg',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue