From 39f6c88f2f2c855eff8452a33fd91b28fc402f19 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Sun, 5 May 2024 21:48:05 -0500 Subject: [PATCH 01/11] Truncate github URL for max length, if needed (#1461) --- src/core/AppCrash.tsx | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/core/AppCrash.tsx b/src/core/AppCrash.tsx index c76626ab0..f2b387168 100644 --- a/src/core/AppCrash.tsx +++ b/src/core/AppCrash.tsx @@ -39,7 +39,7 @@ export default function AppCrash({ error }: FallbackProps) { const location = memoryHistory ? memoryHistory.location : window.location; const loggedIn = loggedInSelector(store.getState()); - const crashData = ` + let crashData = ` ### Crash description @@ -58,15 +58,15 @@ export default function AppCrash({ error }: FallbackProps) { ### Crash data -Error: \`${error}\` +Error: \`\`${error}\`\` #### Stack trace -\`\`\` -${error instanceof Error ? error.stack : "Not available"} \`\`\` `.trim(); + crashData = `${crashData}\n${error instanceof Error ? error.stack : "Not available"}`; + async function clearData() { if ( !confirm( @@ -94,9 +94,7 @@ ${error instanceof Error ? error.stack : "Not available"} voluntarily submitting this crash for us to investigate. ); } + +function generateCrashUrl(crashData: string): string { + return `https://github.com/aeharding/voyager/issues/new?title=Crash&body=${encodeURIComponent( + crashData, + )}`; +} + +// The GitHub GET endpoint for opening a new issue +// has a restriction for maximum length of a URL: 8192 bytes +// https://github.com/cli/cli/pull/3271 +// https://github.com/cli/cli/issues/1575 +// https://github.com/cli/cli/blob/trunk/pkg/cmd/issue/create/create.go#L167 +// https://github.com/cli/cli/blob/trunk/utils/utils.go#L84 +const maxIssueBytes = 8150; + +function getStrByteLength(str: string): number { + return new TextEncoder().encode(str).length; +} + +function generateTruncatedCrashUrl(crashData: string): string { + let url: string; + let strLength = 1; + + do { + url = generateCrashUrl(crashData.slice(0, strLength)); + if (strLength === crashData.length) return url; + strLength++; + } while (getStrByteLength(url) < maxIssueBytes); + + return url; +} From 9b388b0546d841e0a49b1aa31ed5ce9930ffc593 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Sun, 5 May 2024 21:57:36 -0500 Subject: [PATCH 02/11] Fix NSFW messaging visible when image opened with scaling animation (#1462) --- src/features/media/gallery/GalleryProvider.tsx | 10 ++++++++-- .../post/inFeed/large/LargePostContents.tsx | 6 +++++- .../inFeed/large/media/BlurOverlayMessage.tsx | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/features/media/gallery/GalleryProvider.tsx b/src/features/media/gallery/GalleryProvider.tsx index b8a0896b2..3286c453a 100644 --- a/src/features/media/gallery/GalleryProvider.tsx +++ b/src/features/media/gallery/GalleryProvider.tsx @@ -26,6 +26,8 @@ import type ZoomLevel from "photoswipe/dist/types/slide/zoom-level"; import PhotoSwipeLightbox from "photoswipe/lightbox"; import "photoswipe/style.css"; +import { findBlurOverlayContainer } from "../../post/inFeed/large/media/BlurOverlayMessage"; +import { compact } from "lodash"; interface IGalleryContext { // used for determining whether page needs to be scrolled up first @@ -173,13 +175,17 @@ export default function GalleryProvider({ children }: GalleryProviderProps) { instance.on("openingAnimationStart", () => { if (animationType !== "zoom") return; - thumbEl.style.setProperty("visibility", "hidden"); + compact([thumbEl, findBlurOverlayContainer(thumbEl)]).forEach((el) => + el.style.setProperty("visibility", "hidden"), + ); }); const cleanupHideThumb = () => { if (animationType !== "zoom") return; - thumbEl.style.removeProperty("visibility"); + compact([thumbEl, findBlurOverlayContainer(thumbEl)]).forEach((el) => + el.style.removeProperty("visibility"), + ); }; instance.on("closingAnimationEnd", cleanupHideThumb); diff --git a/src/features/post/inFeed/large/LargePostContents.tsx b/src/features/post/inFeed/large/LargePostContents.tsx index 1536c2568..6c5a21b66 100644 --- a/src/features/post/inFeed/large/LargePostContents.tsx +++ b/src/features/post/inFeed/large/LargePostContents.tsx @@ -11,6 +11,10 @@ import { InFeedContext } from "../../../feed/Feed"; import useIsPostUrlMedia from "../../useIsPostUrlMedia"; import PostLink from "../../link/PostLink"; +// This is needed to hide NSFW messaging, etc when image is open +export const LARGE_POST_MEDIA_CONTAINER_CLASSNAME = + "large-post-media-container"; + const PostBody = styled.div` font-size: 0.8em; line-height: 1.25; @@ -64,7 +68,7 @@ export default function LargePostContents({ post }: LargePostContentsProps) { if (urlIsMedia || markdownLoneImage) { return ( - + + NSFW Sensitive content — tap to view ); } + +export function findBlurOverlayContainer( + imgEl: HTMLElement, +): HTMLElement | undefined { + const el = imgEl + .closest(`.${LARGE_POST_MEDIA_CONTAINER_CLASSNAME}`) + ?.querySelector(`.${BLUR_OVERLAY_CONTAINER_CLASSNAME}`); + + if (el instanceof HTMLElement) return el; +} From 2fd0d2c38bbec303d30ddb9d61c19174434da72e Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Mon, 6 May 2024 22:39:29 -0500 Subject: [PATCH 03/11] Add post appearance type toggle from feed, add share home/all/local feeds (#1464) --- src/features/community/MoreActions.tsx | 56 +++++------- src/features/feed/SpecialFeedMoreActions.tsx | 86 +++++++++++++++---- .../settings/appearance/posts/PostSize.tsx | 5 ++ src/routes/pages/shared/SpecialFeedPage.tsx | 2 +- 4 files changed, 100 insertions(+), 49 deletions(-) diff --git a/src/features/community/MoreActions.tsx b/src/features/community/MoreActions.tsx index 8058dbfdb..1d115c1dd 100644 --- a/src/features/community/MoreActions.tsx +++ b/src/features/community/MoreActions.tsx @@ -1,4 +1,4 @@ -import { IonActionSheet, IonButton } from "@ionic/react"; +import { IonButton, useIonActionSheet } from "@ionic/react"; import { createOutline, heartDislikeOutline, @@ -10,49 +10,30 @@ import { eyeOffOutline, shareOutline, } from "ionicons/icons"; -import { useState } from "react"; import useHidePosts from "../feed/useHidePosts"; import useCommunityActions from "./useCommunityActions"; import { Community, CommunityView } from "lemmy-js-client"; import { useAppSelector } from "../../store"; import { compact } from "lodash"; import HeaderEllipsisIcon from "../shared/HeaderEllipsisIcon"; +import { buildTogglePostAppearanceButton } from "../feed/SpecialFeedMoreActions"; interface MoreActionsProps { community: CommunityView | undefined; } export default function MoreActions({ community }: MoreActionsProps) { - const [open, setOpen] = useState(false); + if (!community) return buildButtonJsx(); - return ( - <> - setOpen(true)}> - - - - {community && ( - - )} - - ); + return ; } interface MoreActionsActionSheetProps { community: Community; - open: boolean; - setOpen: (open: boolean) => void; } -function MoreActionsActionSheet({ - community, - open, - setOpen, -}: MoreActionsActionSheetProps) { +function MoreActionsWithCommunity({ community }: MoreActionsActionSheetProps) { + const [presentActionSheet] = useIonActionSheet(); const { isSubscribed, isBlocked, @@ -70,11 +51,10 @@ function MoreActionsActionSheet({ (state) => state.settings.general.posts.showHiddenInCommunities, ); - return ( - setOpen(false)} - /> + ]), + }); + } + + return buildButtonJsx(present); +} + +function buildButtonJsx(onClick?: () => void) { + return ( + + + ); } diff --git a/src/features/feed/SpecialFeedMoreActions.tsx b/src/features/feed/SpecialFeedMoreActions.tsx index 2766906af..5e15b251b 100644 --- a/src/features/feed/SpecialFeedMoreActions.tsx +++ b/src/features/feed/SpecialFeedMoreActions.tsx @@ -1,27 +1,60 @@ import { IonButton, useIonActionSheet } from "@ionic/react"; -import { eyeOffOutline } from "ionicons/icons"; +import { + eyeOffOutline, + imageOutline, + listOutline, + shareOutline, +} from "ionicons/icons"; import useHidePosts from "./useHidePosts"; import HeaderEllipsisIcon from "../shared/HeaderEllipsisIcon"; +import { Share } from "@capacitor/share"; +import { ListingType } from "lemmy-js-client"; +import store from "../../store"; +import { urlSelector } from "../auth/authSelectors"; +import { + OPostAppearanceType, + setPostAppearance, +} from "../settings/settingsSlice"; -export default function SpecialFeedMoreActions() { - const [presentActionSheet] = useIonActionSheet(); +interface SpecialFeedMoreActionsProps { + type: ListingType; +} +export default function SpecialFeedMoreActions({ + type, +}: SpecialFeedMoreActionsProps) { + const [presentActionSheet] = useIonActionSheet(); const hidePosts = useHidePosts(); function present() { - presentActionSheet([ - { - text: "Hide Read Posts", - icon: eyeOffOutline, - handler: () => { - hidePosts(); + presentActionSheet({ + cssClass: "left-align-buttons", + buttons: [ + { + text: "Hide Read Posts", + icon: eyeOffOutline, + handler: () => { + hidePosts(); + }, }, - }, - { - text: "Cancel", - role: "cancel", - }, - ]); + buildTogglePostAppearanceButton(), + { + text: "Share", + icon: shareOutline, + handler: () => { + const url = urlSelector(store.getState()); + + Share.share({ + url: `https://${url}?dataType=Post&listingType=${type}`, + }); + }, + }, + { + text: "Cancel", + role: "cancel", + }, + ], + }); } return ( @@ -30,3 +63,26 @@ export default function SpecialFeedMoreActions() { ); } + +export function buildTogglePostAppearanceButton() { + const postAppearanceType = store.getState().settings.appearance.posts.type; + + switch (postAppearanceType) { + case OPostAppearanceType.Compact: + return { + text: "Large Posts", + icon: imageOutline, + handler: () => { + store.dispatch(setPostAppearance(OPostAppearanceType.Large)); + }, + }; + case OPostAppearanceType.Large: + return { + text: "Compact Posts", + icon: listOutline, + handler: () => { + store.dispatch(setPostAppearance(OPostAppearanceType.Compact)); + }, + }; + } +} diff --git a/src/features/settings/appearance/posts/PostSize.tsx b/src/features/settings/appearance/posts/PostSize.tsx index 7681f86dc..d069c09b3 100644 --- a/src/features/settings/appearance/posts/PostSize.tsx +++ b/src/features/settings/appearance/posts/PostSize.tsx @@ -1,6 +1,7 @@ import { OPostAppearanceType, setPostAppearance } from "../../settingsSlice"; import { useAppSelector } from "../../../../store"; import SettingSelector from "../../shared/SettingSelector"; +import { imageOutline, listOutline } from "ionicons/icons"; export default function PostSize() { const postsAppearanceType = useAppSelector( @@ -13,6 +14,10 @@ export default function PostSize() { selected={postsAppearanceType} setSelected={setPostAppearance} options={OPostAppearanceType} + optionIcons={{ + [OPostAppearanceType.Compact]: listOutline, + [OPostAppearanceType.Large]: imageOutline, + }} /> ); } diff --git a/src/routes/pages/shared/SpecialFeedPage.tsx b/src/routes/pages/shared/SpecialFeedPage.tsx index 35bcf20b5..5d3a212b1 100644 --- a/src/routes/pages/shared/SpecialFeedPage.tsx +++ b/src/routes/pages/shared/SpecialFeedPage.tsx @@ -109,7 +109,7 @@ export default function SpecialFeedPage({ type }: SpecialFeedProps) { {type === "ModeratorView" && } - + From 1d74518743d93a305b0ad308a38b49e8376a51fa Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Wed, 8 May 2024 22:50:49 -0500 Subject: [PATCH 04/11] Remember comment sort by community (#1465) * Add remember comment sort * Add migration * Fallback for broken indexeddb --- src/features/comment/CommentSort.tsx | 4 +- src/features/feed/sort/feedSortSlice.tsx | 75 ++++++++++++++----- src/features/feed/sort/useFeedSort.tsx | 47 ++++++++---- .../settings/general/comments/Comments.tsx | 2 + .../comments/RememberCommunityCommentSort.tsx | 24 ++++++ src/features/settings/general/posts/Posts.tsx | 4 +- ...Sort.tsx => RememberCommunityPostSort.tsx} | 10 +-- src/features/settings/settingsSlice.tsx | 26 +++++-- src/routes/pages/posts/PostPage.tsx | 19 +++-- .../search/results/SearchCommunitiesPage.tsx | 4 +- .../search/results/SearchFeedResultsPage.tsx | 4 +- src/routes/pages/shared/CommunityPage.tsx | 4 +- src/routes/pages/shared/SpecialFeedPage.tsx | 4 +- src/services/db.ts | 11 ++- 14 files changed, 178 insertions(+), 60 deletions(-) create mode 100644 src/features/settings/general/comments/RememberCommunityCommentSort.tsx rename src/features/settings/general/posts/{RememberCommunitySort.tsx => RememberCommunityPostSort.tsx} (58%) diff --git a/src/features/comment/CommentSort.tsx b/src/features/comment/CommentSort.tsx index e14d64e4b..ebbb4a87d 100644 --- a/src/features/comment/CommentSort.tsx +++ b/src/features/comment/CommentSort.tsx @@ -36,7 +36,7 @@ const BUTTONS: ActionSheetButton[] = COMMENT_SORTS.map( ); interface CommentSortProps { - sort: CommentSortType; + sort: CommentSortType | undefined; setSort: (sort: CommentSortType) => void; } @@ -44,6 +44,8 @@ export default function CommentSort({ sort, setSort }: CommentSortProps) { const [open, setOpen] = useState(false); const { activePageRef } = useContext(AppContext); + if (!sort) return; + return ( <> setOpen(true)}> diff --git a/src/features/feed/sort/feedSortSlice.tsx b/src/features/feed/sort/feedSortSlice.tsx index 6f3e48dfd..8648e24dd 100644 --- a/src/features/feed/sort/feedSortSlice.tsx +++ b/src/features/feed/sort/feedSortSlice.tsx @@ -1,5 +1,5 @@ import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; -import { ListingType, SortType } from "lemmy-js-client"; +import { CommentSortType, ListingType, SortType } from "lemmy-js-client"; import { db } from "../../../services/db"; import { RootState } from "../../../store"; import { getFeedUrlName } from "../../community/mod/ModActions"; @@ -8,34 +8,54 @@ interface PostSortState { /** * `null`: Loaded from database, but nothing there */ - sortByFeedName: Record; + sortByContextByFeedName: { + posts: Record; + comments: Record; + }; } const initialState: PostSortState = { - sortByFeedName: {}, + sortByContextByFeedName: { + posts: {}, + comments: {}, + }, }; +export type SetSortActionPayload = + | { + feed: FeedSortFeed; + sort: SortType; + context: "posts"; + } + | { + feed: FeedSortFeed; + sort: CommentSortType; + context: "comments"; + }; + export const feedSortSlice = createSlice({ name: "feedSort", initialState, reducers: { - setFeedSort: ( - state, - action: PayloadAction<{ feed: FeedSortFeed; sort: SortType }>, - ) => { + setFeedSort: (state, action: PayloadAction) => { const feedName = serializeFeedName(action.payload.feed); - state.sortByFeedName[feedName] = action.payload.sort; + state.sortByContextByFeedName[action.payload.context][feedName] = + action.payload.sort; - db.setSetting("default_post_sort_by_feed", action.payload.sort, { - community: feedName, - }); + db.setSetting( + getDefaultSortSettingForContext(action.payload.context), + action.payload.sort, + { + community: feedName, + }, + ); }, }, extraReducers: (builder) => { builder.addCase(getFeedSort.fulfilled, (state, action) => { - const { feedName, sort } = action.payload; + const { feedName, sort, context } = action.payload; - state.sortByFeedName[feedName] = sort; + state.sortByContextByFeedName[context][feedName] = sort; }); }, }); @@ -55,23 +75,33 @@ export type FeedSortFeed = export const getFeedSort = createAsyncThunk( "feedSort/getFeedSort", - async (feed: FeedSortFeed) => { + async ({ + feed, + context, + }: { + feed: FeedSortFeed; + context: "posts" | "comments"; + }) => { const feedName = serializeFeedName(feed); const sort = - (await db.getSetting("default_post_sort_by_feed", { + (await db.getSetting(getDefaultSortSettingForContext(context), { community: feedName, - })) ?? null; + })) ?? null; // null = loaded, but not found return { feedName, sort, + context, }; }, ); export const getFeedSortSelectorBuilder = - (feed: FeedSortFeed | undefined) => (state: RootState) => - feed ? state.feedSort.sortByFeedName[serializeFeedName(feed)] : null; + (feed: FeedSortFeed | undefined, context: "posts" | "comments") => + (state: RootState) => + feed + ? state.feedSort.sortByContextByFeedName[context][serializeFeedName(feed)] + : null; function serializeFeedName(feed: FeedSortFeed): string { switch (true) { @@ -83,3 +113,12 @@ function serializeFeedName(feed: FeedSortFeed): string { return feed; } } + +function getDefaultSortSettingForContext(context: "posts" | "comments") { + switch (context) { + case "comments": + return "default_comment_sort_by_feed"; + case "posts": + return "default_post_sort_by_feed"; + } +} diff --git a/src/features/feed/sort/useFeedSort.tsx b/src/features/feed/sort/useFeedSort.tsx index 1d828bb97..99a88958b 100644 --- a/src/features/feed/sort/useFeedSort.tsx +++ b/src/features/feed/sort/useFeedSort.tsx @@ -1,49 +1,68 @@ -import { SortType } from "lemmy-js-client"; +import { CommentSortType, SortType } from "lemmy-js-client"; import { useEffect, useState } from "react"; import { useAppDispatch, useAppSelector } from "../../../store"; import { FeedSortFeed, + SetSortActionPayload, getFeedSort, getFeedSortSelectorBuilder, setFeedSort, } from "./feedSortSlice"; -export default function useFeedSort(feed?: FeedSortFeed | undefined) { +type SortTypeByContext = { + posts: SortType; + comments: CommentSortType; +}; + +export default function useSortByFeed< + Context extends "posts" | "comments", + Sort extends SortTypeByContext[Context], +>(context: Context, feed?: FeedSortFeed | undefined) { const dispatch = useAppDispatch(); - const feedSort = useAppSelector(getFeedSortSelectorBuilder(feed)); + const feedSort = useAppSelector( + getFeedSortSelectorBuilder(feed, context), + ) as Sort; const defaultSort = useAppSelector( - (state) => state.settings.general.posts.sort, - ); + (state) => state.settings.general[context].sort, + ) as Sort; const rememberCommunitySort = useAppSelector( - (state) => state.settings.general.posts.rememberCommunitySort, + (state) => state.settings.general[context].rememberCommunitySort, ); - const [sort, _setSort] = useState( + const [sort, _setSort] = useState( !rememberCommunitySort ? defaultSort : undefined, ); useEffect(() => { - if (!rememberCommunitySort) return; - if (!feed) return; + (async () => { + if (!rememberCommunitySort) return; + if (!feed) return; - dispatch(getFeedSort(feed)); - }, [feed, dispatch, rememberCommunitySort]); + try { + await dispatch(getFeedSort({ feed, context })); + } catch (error) { + _setSort((_sort) => _sort ?? defaultSort); // fallback if indexeddb unavailable + throw error; + } + })(); + }, [feed, dispatch, rememberCommunitySort, context, defaultSort]); useEffect(() => { if (!rememberCommunitySort) return; if (sort) return; - if (feedSort === undefined) return; + if (feedSort === undefined) return; // null = loaded, but custom community sort not found _setSort(feedSort ?? defaultSort); }, [feedSort, sort, defaultSort, rememberCommunitySort]); - function setSort(sort: SortType) { + function setSort(sort: Sort) { if (rememberCommunitySort && feed) { dispatch( setFeedSort({ feed, sort, - }), + context, + } as SetSortActionPayload), ); } diff --git a/src/features/settings/general/comments/Comments.tsx b/src/features/settings/general/comments/Comments.tsx index 7fe31bc51..97773f742 100644 --- a/src/features/settings/general/comments/Comments.tsx +++ b/src/features/settings/general/comments/Comments.tsx @@ -9,6 +9,7 @@ import TouchFriendlyLinks from "./TouchFriendlyLinks"; import TapToCollapse from "./TapToCollapse"; import ShowCommentImages from "./ShowCommentImages"; import ShowCollapsed from "./ShowCollapsed"; +import RememberCommunityCommentSort from "./RememberCommunityCommentSort"; export default function Comments() { return ( @@ -18,6 +19,7 @@ export default function Comments() { + diff --git a/src/features/settings/general/comments/RememberCommunityCommentSort.tsx b/src/features/settings/general/comments/RememberCommunityCommentSort.tsx new file mode 100644 index 000000000..c1fff43c6 --- /dev/null +++ b/src/features/settings/general/comments/RememberCommunityCommentSort.tsx @@ -0,0 +1,24 @@ +import { IonItem, IonToggle } from "@ionic/react"; + +import { useAppDispatch, useAppSelector } from "../../../../store"; +import { setRememberCommunityCommentSort } from "../../settingsSlice"; + +export default function RememberCommunityCommentSort() { + const dispatch = useAppDispatch(); + const rememberCommunitySort = useAppSelector( + (state) => state.settings.general.comments.rememberCommunitySort, + ); + + return ( + + + dispatch(setRememberCommunityCommentSort(e.detail.checked)) + } + > + Remember Community Sort + + + ); +} diff --git a/src/features/settings/general/posts/Posts.tsx b/src/features/settings/general/posts/Posts.tsx index c65460bef..7d8fffa43 100644 --- a/src/features/settings/general/posts/Posts.tsx +++ b/src/features/settings/general/posts/Posts.tsx @@ -3,7 +3,7 @@ import { ListHeader } from "../../shared/formatting"; import InfiniteScrolling from "./InfiniteScrolling"; import UpvoteOnSave from "./UpvoteOnSave"; import DefaultSort from "./DefaultSort"; -import RememberCommunitySort from "./RememberCommunitySort"; +import RememberCommunityPostSort from "./RememberCommunityPostSort"; import AutoplayMedia from "./AutoplayMedia"; export default function Posts() { @@ -19,7 +19,7 @@ export default function Posts() { - + diff --git a/src/features/settings/general/posts/RememberCommunitySort.tsx b/src/features/settings/general/posts/RememberCommunityPostSort.tsx similarity index 58% rename from src/features/settings/general/posts/RememberCommunitySort.tsx rename to src/features/settings/general/posts/RememberCommunityPostSort.tsx index 814aa8943..5290e45d0 100644 --- a/src/features/settings/general/posts/RememberCommunitySort.tsx +++ b/src/features/settings/general/posts/RememberCommunityPostSort.tsx @@ -1,20 +1,20 @@ import { IonItem, IonToggle } from "@ionic/react"; import { useAppDispatch, useAppSelector } from "../../../../store"; -import { setRememberCommunitySort } from "../../settingsSlice"; +import { setRememberCommunityPostSort } from "../../settingsSlice"; -export default function RememberCommunitySort() { +export default function RememberCommunityPostSort() { const dispatch = useAppDispatch(); - const infiniteScrolling = useAppSelector( + const rememberCommunitySort = useAppSelector( (state) => state.settings.general.posts.rememberCommunitySort, ); return ( - dispatch(setRememberCommunitySort(e.detail.checked)) + dispatch(setRememberCommunityPostSort(e.detail.checked)) } > Remember Community Sort diff --git a/src/features/settings/settingsSlice.tsx b/src/features/settings/settingsSlice.tsx index a6720e480..6ec695729 100644 --- a/src/features/settings/settingsSlice.tsx +++ b/src/features/settings/settingsSlice.tsx @@ -110,6 +110,7 @@ interface SettingsState { touchFriendlyLinks: boolean; showCommentImages: boolean; showCollapsed: boolean; + rememberCommunitySort: boolean; }; posts: { sort: SortType; @@ -206,6 +207,7 @@ export const initialState: SettingsState = { touchFriendlyLinks: true, showCommentImages: true, showCollapsed: false, + rememberCommunitySort: false, }, posts: { sort: "Active", @@ -483,10 +485,15 @@ export const appearanceSlice = createSlice({ db.setSetting("upvote_on_save", action.payload); }, - setRememberCommunitySort(state, action: PayloadAction) { + setRememberCommunityPostSort(state, action: PayloadAction) { state.general.posts.rememberCommunitySort = action.payload; - db.setSetting("remember_community_sort", action.payload); + db.setSetting("remember_community_post_sort", action.payload); + }, + setRememberCommunityCommentSort(state, action: PayloadAction) { + state.general.comments.rememberCommunitySort = action.payload; + + db.setSetting("remember_community_comment_sort", action.payload); }, setAutoplayMedia(state, action: PayloadAction) { state.general.posts.autoplayMedia = action.payload; @@ -673,8 +680,11 @@ export const fetchSettingsFromDatabase = createAsyncThunk( ); const infinite_scrolling = await db.getSetting("infinite_scrolling"); const upvote_on_save = await db.getSetting("upvote_on_save"); - const remember_community_sort = await db.getSetting( - "remember_community_sort", + const remember_community_post_sort = await db.getSetting( + "remember_community_post_sort", + ); + const remember_community_comment_sort = await db.getSetting( + "remember_community_comment_sort", ); const autoplay_media = await db.getSetting("autoplay_media"); const enable_haptic_feedback = await db.getSetting( @@ -787,6 +797,9 @@ export const fetchSettingsFromDatabase = createAsyncThunk( showCollapsed: show_collapsed_comment ?? initialState.general.comments.showCollapsed, + rememberCommunitySort: + remember_community_comment_sort ?? + initialState.general.comments.rememberCommunitySort, }, posts: { disableMarkingRead: @@ -813,7 +826,7 @@ export const fetchSettingsFromDatabase = createAsyncThunk( upvote_on_save ?? initialState.general.posts.upvoteOnSave, sort: default_post_sort ?? initialState.general.posts.sort, rememberCommunitySort: - remember_community_sort ?? + remember_community_post_sort ?? initialState.general.posts.rememberCommunitySort, autoplayMedia: autoplay_media ?? initialState.general.posts.autoplayMedia, @@ -893,7 +906,8 @@ export const { setDisableAutoHideInCommunities, setInfiniteScrolling, setUpvoteOnSave, - setRememberCommunitySort, + setRememberCommunityPostSort, + setRememberCommunityCommentSort, setAutoplayMedia, setTheme, setEnableHapticFeedback, diff --git a/src/routes/pages/posts/PostPage.tsx b/src/routes/pages/posts/PostPage.tsx index 7061841ff..e6c9fb626 100644 --- a/src/routes/pages/posts/PostPage.tsx +++ b/src/routes/pages/posts/PostPage.tsx @@ -14,9 +14,8 @@ import { import { useAppDispatch, useAppSelector } from "../../../store"; import { useParams } from "react-router"; import { styled } from "@linaria/react"; -import React, { memo, useCallback, useEffect, useState } from "react"; +import React, { memo, useCallback, useEffect } from "react"; import { getPost } from "../../../features/post/postSlice"; -import { CommentSortType } from "lemmy-js-client"; import { useBuildGeneralBrowseLink } from "../../../helpers/routes"; import CommentSort from "../../../features/comment/CommentSort"; import MoreActions from "../../../features/post/shared/MoreActions"; @@ -28,6 +27,8 @@ import MoreModActions from "../../../features/post/shared/MoreModAction"; import { useSetActivePage } from "../../../features/auth/AppContext"; import { useRef } from "react"; import AppHeader from "../../../features/shared/AppHeader"; +import useSortByFeed from "../../../features/feed/sort/useFeedSort"; +import { getRemoteHandleFromHandle } from "../../../helpers/lemmy"; export const CenteredSpinner = styled(IonSpinner)` position: relative; @@ -74,10 +75,16 @@ const PostPageContent = memo(function PostPageContent({ const post = useAppSelector((state) => state.post.postById[id]); const client = useClient(); const dispatch = useAppDispatch(); - const defaultSort = useAppSelector( - (state) => state.settings.general.comments.sort, + + const connectedInstance = useAppSelector( + (state) => state.auth.connectedInstance, ); - const [sort, setSort] = useState(defaultSort); + const [sort, setSort] = useSortByFeed("comments", { + remoteCommunityHandle: getRemoteHandleFromHandle( + community, + connectedInstance, + ), + }); const postDeletedById = useAppSelector((state) => state.post.postDeletedById); const postIfFound = typeof post === "object" ? post : undefined; @@ -135,6 +142,8 @@ const PostPageContent = memo(function PostPageContent({
Post not found
, ); + if (!sort) return; + return ( (); const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const client = useClient(); - const [sort, setSort] = useFeedSort(); + const [sort, setSort] = useSortByFeed("posts"); const search = decodeURIComponent(_encodedSearch); diff --git a/src/routes/pages/search/results/SearchFeedResultsPage.tsx b/src/routes/pages/search/results/SearchFeedResultsPage.tsx index 20806ad4c..c3aa85a67 100644 --- a/src/routes/pages/search/results/SearchFeedResultsPage.tsx +++ b/src/routes/pages/search/results/SearchFeedResultsPage.tsx @@ -20,7 +20,7 @@ import { receivedPosts } from "../../../../features/post/postSlice"; import { receivedComments } from "../../../../features/comment/commentSlice"; import FeedContent from "../../shared/FeedContent"; import { getSortDuration } from "../../../../features/feed/endItems/EndPost"; -import useFeedSort from "../../../../features/feed/sort/useFeedSort"; +import useSortByFeed from "../../../../features/feed/sort/useFeedSort"; import AppHeader from "../../../../features/shared/AppHeader"; interface SearchPostsResultsProps { @@ -37,7 +37,7 @@ export default function SearchFeedResultsPage({ }>(); const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const client = useClient(); - const [sort, setSort] = useFeedSort(); + const [sort, setSort] = useSortByFeed("posts"); const search = decodeURIComponent(_encodedSearch); diff --git a/src/routes/pages/shared/CommunityPage.tsx b/src/routes/pages/shared/CommunityPage.tsx index 55d559bea..24ed3d0ba 100644 --- a/src/routes/pages/shared/CommunityPage.tsx +++ b/src/routes/pages/shared/CommunityPage.tsx @@ -34,7 +34,7 @@ import CommunitySearchResults from "../../../features/community/search/Community import { getSortDuration } from "../../../features/feed/endItems/EndPost"; import ModActions from "../../../features/community/mod/ModActions"; import { useOptimizedIonRouter } from "../../../helpers/useOptimizedIonRouter"; -import useFeedSort from "../../../features/feed/sort/useFeedSort"; +import useSortByFeed from "../../../features/feed/sort/useFeedSort"; import { CenteredSpinner } from "../posts/PostPage"; import { getRemoteHandleFromHandle } from "../../../helpers/lemmy"; import { useAppSelector } from "../../../store"; @@ -155,7 +155,7 @@ const CommunityPageContent = memo(function CommunityPageContent({ (state) => state.settings.general.posts.showHiddenInCommunities, ); - const [sort, setSort] = useFeedSort({ + const [sort, setSort] = useSortByFeed("posts", { remoteCommunityHandle: getRemoteHandleFromHandle( community, connectedInstance, diff --git a/src/routes/pages/shared/SpecialFeedPage.tsx b/src/routes/pages/shared/SpecialFeedPage.tsx index 5d3a212b1..bd367de84 100644 --- a/src/routes/pages/shared/SpecialFeedPage.tsx +++ b/src/routes/pages/shared/SpecialFeedPage.tsx @@ -22,7 +22,7 @@ import { followIdsSelector } from "../../../features/auth/siteSlice"; import { getHandle } from "../../../helpers/lemmy"; import { CenteredSpinner } from "../posts/PostPage"; import ModActions from "../../../features/community/mod/ModActions"; -import useFeedSort from "../../../features/feed/sort/useFeedSort"; +import useSortByFeed from "../../../features/feed/sort/useFeedSort"; import { PageTypeContext } from "../../../features/feed/PageTypeContext"; import AppHeader from "../../../features/shared/AppHeader"; @@ -34,7 +34,7 @@ export default function SpecialFeedPage({ type }: SpecialFeedProps) { const buildGeneralBrowseLink = useBuildGeneralBrowseLink(); const client = useClient(); - const [sort, setSort] = useFeedSort({ listingType: type }); + const [sort, setSort] = useSortByFeed("posts", { listingType: type }); const followIds = useAppSelector(followIdsSelector); const communityByHandle = useAppSelector( diff --git a/src/services/db.ts b/src/services/db.ts index b886ee4cb..6e8950f66 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -306,6 +306,7 @@ export type SettingValueTypes = { favorite_communities: string[]; migration_links: string[]; default_comment_sort: CommentDefaultSort; + default_comment_sort_by_feed: CommentDefaultSort; disable_marking_posts_read: boolean; mark_read_on_scroll: boolean; show_hide_read_button: boolean; @@ -338,7 +339,8 @@ export type SettingValueTypes = { upvote_on_save: boolean; default_post_sort: SortType; default_post_sort_by_feed: SortType; - remember_community_sort: boolean; + remember_community_post_sort: boolean; + remember_community_comment_sort: boolean; embed_crossposts: boolean; show_community_icons: boolean; autoplay_media: AutoplayMediaType; @@ -502,6 +504,13 @@ export class WefwefDB extends Dexie { data `, }); + + this.version(8).upgrade(async () => { + await this.settings + .where("key") + .equals("remember_community_sort") + .modify({ key: "remember_community_post_sort" }); + }); } /* From 0e10348025a945e76bc26837491b907407fc2ec6 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Thu, 9 May 2024 17:32:46 -0500 Subject: [PATCH 05/11] Cleanup function definition --- src/features/feed/sort/useFeedSort.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/features/feed/sort/useFeedSort.tsx b/src/features/feed/sort/useFeedSort.tsx index 99a88958b..7a53d7af6 100644 --- a/src/features/feed/sort/useFeedSort.tsx +++ b/src/features/feed/sort/useFeedSort.tsx @@ -9,15 +9,15 @@ import { setFeedSort, } from "./feedSortSlice"; -type SortTypeByContext = { - posts: SortType; - comments: CommentSortType; -}; +export default function useSortByFeed( + context: Context, + feed?: FeedSortFeed | undefined, +) { + type Sort = { + posts: SortType; + comments: CommentSortType; + }[Context]; -export default function useSortByFeed< - Context extends "posts" | "comments", - Sort extends SortTypeByContext[Context], ->(context: Context, feed?: FeedSortFeed | undefined) { const dispatch = useAppDispatch(); const feedSort = useAppSelector( getFeedSortSelectorBuilder(feed, context), From ddf7600196b5422dbee443f0158731a10c0394c4 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Thu, 9 May 2024 17:42:41 -0500 Subject: [PATCH 06/11] Fix cancel button on compose new private message alert (#1467) Fixes #1466 --- src/routes/pages/inbox/ComposeButton.tsx | 47 +++++++++++++----------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/routes/pages/inbox/ComposeButton.tsx b/src/routes/pages/inbox/ComposeButton.tsx index 205f44150..64b75a745 100644 --- a/src/routes/pages/inbox/ComposeButton.tsx +++ b/src/routes/pages/inbox/ComposeButton.tsx @@ -1,4 +1,4 @@ -import { IonAlert, IonButton, IonIcon, IonLoading } from "@ionic/react"; +import { IonButton, IonIcon, IonLoading, useIonAlert } from "@ionic/react"; import { createOutline } from "ionicons/icons"; import { useState } from "react"; import { useAppDispatch } from "../../../store"; @@ -10,10 +10,10 @@ import { isLemmyError } from "../../../helpers/lemmyErrors"; export default function ComposeButton() { const [loading, setLoading] = useState(false); - const [isAlertOpen, setIsAlertOpen] = useState(false); const router = useOptimizedIonRouter(); const dispatch = useAppDispatch(); const presentToast = useAppToast(); + const [presentAlert] = useIonAlert(); async function composeNew(handle: string) { setLoading(true); @@ -38,28 +38,33 @@ export default function ComposeButton() { router.push(`/inbox/messages/${getHandle(user.person_view.person)}`); } + function present() { + presentAlert({ + header: "Compose new message", + inputs: [ + { + name: "handle", + placeholder: "user@instance", + }, + ], + buttons: [ + { + text: "OK", + handler: (e) => { + if (!e.handle) return; + + composeNew(e.handle); + }, + }, + { text: "Cancel", role: "cancel" }, + ], + }); + } + return ( <> - { - setIsAlertOpen(false); - - if (!e.detail.data) return; - - composeNew(e.detail.data.values.handle); - }} - inputs={[ - { - name: "handle", - placeholder: "user@instance", - }, - ]} - buttons={[{ text: "OK" }, { text: "Cancel", role: "cancel" }]} - /> - setIsAlertOpen(true)}> + From 11e04fe930e23c3f69ac09a4b079ad71619501a2 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Thu, 9 May 2024 17:52:58 -0500 Subject: [PATCH 07/11] (chore) Simplify native onboarding, install @ionic/cli to dev deps (#1468) --- CONTRIBUTING.md | 26 ++-- package.json | 1 + pnpm-lock.yaml | 400 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 413 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c901342f..1d9c6f1bb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,37 +49,35 @@ pnpm run dev If the feature you're working on is native-only, you can compile and run Voyager in an iOS Simulator or real device. -To build the iOS native app: +To build the iOS native app, install: -1. Install [Node](https://nodejs.org/en) -2. Install [Ionic CLI](https://ionicframework.com/docs/cli) -3. Install [Xcode](https://developer.apple.com/xcode/) -4. [Cocoapods](https://cocoapods.org/) +1. [Node](https://nodejs.org) +2. [Xcode](https://developer.apple.com/xcode/) +3. [Cocoapods](https://cocoapods.org) -Then, build the project and copy web dependencies over: +Then, in Voyager's source code directory, build the project: ```sh corepack enable pnpm install -ionic capacitor build ios +pnpm exec ionic capacitor build ios ``` -Finally, can run the project with `CMD+R`. +Xcode should automatically open. You can then run the project with `CMD+R`. ### Android Native App -To build the Android native app: +To build the Android native app, install: -1. Install [Node](https://nodejs.org/en) -2. Install [Ionic CLI](https://ionicframework.com/docs/cli) -3. Install [Android Studio](https://developer.android.com/studio) +1. [Node](https://nodejs.org) +2. [Android Studio](https://developer.android.com/studio) -In Voyager source code directory: +Then, in Voyager's source code directory, build the project: ```sh corepack enable pnpm install -ionic capacitor build android +pnpm exec ionic capacitor build android ``` Android Studio should open. diff --git a/package.json b/package.json index b54691123..a9410ee87 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ "@babel/preset-react": "^7.23.3", "@babel/preset-typescript": "^7.23.3", "@capacitor/cli": "^6.0.0", + "@ionic/cli": "^7.2.0", "@playwright/test": "^1.43.0", "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^15.0.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1984ff407..5b6d88127 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -260,6 +260,9 @@ importers: '@capacitor/cli': specifier: ^6.0.0 version: 6.0.0 + '@ionic/cli': + specifier: ^7.2.0 + version: 7.2.0 '@playwright/test': specifier: ^1.43.0 version: 1.43.1 @@ -1430,6 +1433,19 @@ packages: resolution: {integrity: sha512-TshtaFQsovB4NWRBydbNFawql6yul7d5bMiW1WYYf17hd99V6xdDdk3vtF51bw6sLkxON3bDQpWsnUc9/hVo3g==} engines: {node: '>=16.0.0'} + '@ionic/cli-framework-prompts@2.1.13': + resolution: {integrity: sha512-Yj1fz6p7OehreQ8C70bd9+M6tYP/rvzLw5JVj8pT/N9s0kQSjqEFRbs96LKr3lfd3TADZaS8OlZrQIqenFIUpg==} + engines: {node: '>=16.0.0'} + + '@ionic/cli-framework@6.0.1': + resolution: {integrity: sha512-Fyix4eQt2HKTV+GoeoiziQGZyqIA8RfoMqjGyAS5XgNXLOYW0P27Ph348hQZh9Mphjf+m0lOYa6dWQTEPzUHiQ==} + engines: {node: '>=16.0.0'} + + '@ionic/cli@7.2.0': + resolution: {integrity: sha512-IEms9Df8mJOoWPqgvZEXmqKztttHDFAz+9ewDPZGYv8Xx66Cj7zSen13O2Vf4FuLXhl+U95HXT9sAs4lDwFmcQ==} + engines: {node: '>=16.0.0'} + hasBin: true + '@ionic/react-router@8.1.0': resolution: {integrity: sha512-2f1OHS+1Dgeb7reh7OObl+IzbWzaZOO7IoVPAOg+HbmzzRA3Z/dMi89Mw+xnajOYfhXNPoRSzqYUqWD4OXqi0A==} peerDependencies: @@ -1460,6 +1476,10 @@ packages: resolution: {integrity: sha512-2EknRvMVfhnyhL1VhFkSLa5gOcycK91VnjfrTB0kbqkTFCOXyXgVLI5whzq7SLrgD9t1aqos3lMMQyVzaQ5gVA==} engines: {node: '>=16.0.0'} + '@ionic/utils-network@2.1.7': + resolution: {integrity: sha512-5Q3NdZtSLiLs7ufuX9X293BvAwo8CxaD93Hkp3ODPgctLYErv3nFibhq3j+eguEqUh2um9WNXEUOuQ8x+Sd1fw==} + engines: {node: '>=16.0.0'} + '@ionic/utils-object@2.1.5': resolution: {integrity: sha512-XnYNSwfewUqxq+yjER1hxTKggftpNjFLJH0s37jcrNDwbzmbpFTQTVAp4ikNK4rd9DOebX/jbeZb8jfD86IYxw==} engines: {node: '>=10.3.0'} @@ -1488,6 +1508,10 @@ packages: resolution: {integrity: sha512-4+Kitey1lTA1yGtnigeYNhV/0tggI3lWBMjC7tBs1K9GXa/q7q4CtOISppdh8QgtOhrhAXS2Igp8rbko/Cj+lA==} engines: {node: '>=16.0.0'} + '@ionic/utils-stream@3.1.7': + resolution: {integrity: sha512-eSELBE7NWNFIHTbTC2jiMvh1ABKGIpGdUIvARsNPMNQhxJB3wpwdiVnoBoTYp+5a6UUIww4Kpg7v6S7iTctH1w==} + engines: {node: '>=16.0.0'} + '@ionic/utils-subprocess@2.1.11': resolution: {integrity: sha512-6zCDixNmZCbMCy5np8klSxOZF85kuDyzZSTTQKQP90ZtYNCcPYmuFSzaqDwApJT4r5L3MY3JrqK1gLkc6xiUPw==} engines: {node: '>=10.3.0'} @@ -1496,6 +1520,10 @@ packages: resolution: {integrity: sha512-nGYvyGVjU0kjPUcSRFr4ROTraT3w/7r502f5QJEsMRKTqa4eEzCshtwRk+/mpASm0kgBN5rrjYA5A/OZg8ahqg==} engines: {node: '>=16.0.0'} + '@ionic/utils-subprocess@3.0.1': + resolution: {integrity: sha512-cT4te3AQQPeIM9WCwIg8ohroJ8TjsYaMb2G4ZEgv9YzeDqHZ4JpeIKqG2SoaA3GmVQ3sOfhPM6Ox9sxphV/d1A==} + engines: {node: '>=16.0.0'} + '@ionic/utils-terminal@2.3.3': resolution: {integrity: sha512-RnuSfNZ5fLEyX3R5mtcMY97cGD1A0NVBbarsSQ6yMMfRJ5YHU7hHVyUfvZeClbqkBC/pAqI/rYJuXKCT9YeMCQ==} engines: {node: '>=10.3.0'} @@ -2842,6 +2870,10 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + cli-width@3.0.0: + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} + cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} engines: {node: '>= 12'} @@ -2916,6 +2948,9 @@ packages: compare-versions@6.1.0: resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -3002,6 +3037,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + core-js-compat@3.37.0: resolution: {integrity: sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA==} @@ -3312,6 +3350,9 @@ packages: resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} engines: {node: '>=10'} + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -3515,6 +3556,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -3566,6 +3611,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -3579,6 +3627,10 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -3636,6 +3688,9 @@ packages: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} + formidable@2.1.2: + resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==} + formidable@3.5.1: resolution: {integrity: sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og==} @@ -3990,6 +4045,10 @@ packages: resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} engines: {node: '>= 14'} + human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -4062,6 +4121,10 @@ packages: inline-style-parser@0.2.3: resolution: {integrity: sha512-qlD8YNDqyTKTyuITrDOffsl6Tdhv+UC4hcdAVuQsK4IMQ99nSgd1MIA/Q+jQYoh9r3hVUXhYh7urSRmXPkW04g==} + inquirer@7.3.3: + resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} + engines: {node: '>=8.0.0'} + inquirer@9.2.19: resolution: {integrity: sha512-WpxOT71HGsFya6/mj5PUue0sWwbpbiPfAR+332zLj/siB0QA1PZM8v3GepegFV1Op189UxHUCF6y8AySdtOMVA==} engines: {node: '>=18'} @@ -4531,6 +4594,9 @@ packages: resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} engines: {node: '>=14.16'} + leek@0.0.24: + resolution: {integrity: sha512-6PVFIYXxlYF0o6hrAsHtGpTmi06otkwNrMcmQ0K96SeSRHPREPa9J3nJZ1frliVH7XT0XFswoJFQoXsDukzGNQ==} + lemmy-js-client@0.19.4-alpha.18: resolution: {integrity: sha512-CUKRIiINZF2zOfK5WzBDF071LjMmRBFHwiSYBMGJyQP1zu8sPKCb/ptg25WWrf79Y4uOaVLctgHg3oEUXmSUmQ==} @@ -4572,6 +4638,27 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash._baseassign@3.2.0: + resolution: {integrity: sha512-t3N26QR2IdSN+gqSy9Ds9pBu/J1EAFEshKlUHpJG3rvyJOYgcELIxcIeKKfZk7sjOz11cFfzJRsyFry/JyabJQ==} + + lodash._basecopy@3.0.1: + resolution: {integrity: sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==} + + lodash._bindcallback@3.0.1: + resolution: {integrity: sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==} + + lodash._createassigner@3.1.1: + resolution: {integrity: sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==} + + lodash._getnative@3.9.1: + resolution: {integrity: sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==} + + lodash._isiterateecall@3.0.9: + resolution: {integrity: sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==} + + lodash.assign@3.2.0: + resolution: {integrity: sha512-/VVxzgGBmbphasTg51FrztxQJ/VgAUpol6zmJuSVSGcNg4g7FA4z7rQV8Ovr9V3vFBNWZhvKWHfpAytjTVUfFA==} + lodash.capitalize@4.2.1: resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} @@ -4581,6 +4668,12 @@ packages: lodash.escaperegexp@4.1.2: resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + lodash.isarguments@3.1.0: + resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + + lodash.isarray@3.0.4: + resolution: {integrity: sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==} + lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} @@ -4593,9 +4686,15 @@ packages: lodash.isstring@4.0.1: resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.keys@3.1.2: + resolution: {integrity: sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.restparam@3.6.1: + resolution: {integrity: sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==} + lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} @@ -4655,6 +4754,10 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true + macos-release@2.5.1: + resolution: {integrity: sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==} + engines: {node: '>=6'} + macos-release@3.2.0: resolution: {integrity: sha512-fSErXALFNsnowREYZ49XCdOHF8wOPWuFOGQrAhP7x5J/BqQv+B02cNsTykGpDgRVx43EKg++6ANmTaGTtW+hUA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4759,6 +4862,10 @@ packages: mergexml@1.2.4: resolution: {integrity: sha512-yiOlDqcVCz7AG1eSboonc18FTlfqDEKYfGoAV3Lul98u6YRV/s0kjtf4bjk47t0hLTFJR0BSYMd6BpmX3xDjNQ==} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + micromark-core-commonmark@2.0.0: resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==} @@ -4858,6 +4965,11 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -4954,6 +5066,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + mute-stream@1.0.0: resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -5131,6 +5246,10 @@ packages: resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} engines: {node: '>=18'} + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -5147,6 +5266,10 @@ packages: resolution: {integrity: sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==} engines: {node: '>=18'} + os-name@4.0.1: + resolution: {integrity: sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==} + engines: {node: '>=10'} + os-name@5.1.0: resolution: {integrity: sha512-YEIoAnM6zFmzw3PQ201gCVCIWbXNyKObGlVvpAVvraAeOHnlYVKFssbA/riRX5R40WA6kKrZ7Dr7dWzO3nKSeQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -5451,6 +5574,10 @@ packages: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + qs@6.12.1: + resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} + engines: {node: '>=0.6'} + querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} @@ -5775,10 +5902,18 @@ packages: rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} + rsvp@3.6.2: + resolution: {integrity: sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==} + engines: {node: 0.12.* || 4.* || 6.* || >= 7.*} + run-applescript@7.0.0: resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} engines: {node: '>=18'} + run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + run-async@3.0.0: resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} engines: {node: '>=0.12.0'} @@ -5786,6 +5921,10 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -5988,6 +6127,9 @@ packages: sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + ssh-config@1.1.6: + resolution: {integrity: sha512-ZPO9rECxzs5JIQ6G/2EfL1I9ho/BVZkx9HRKn8+0af7QgwAmumQ7XBFP1ggMyPMo+/tUbmv0HFdv4qifdO/9JA==} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -6010,6 +6152,9 @@ packages: resolution: {integrity: sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==} engines: {node: '>= 0.10.0'} + stream-combiner2@1.1.1: + resolution: {integrity: sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==} + streamx@2.16.1: resolution: {integrity: sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==} @@ -6098,6 +6243,11 @@ packages: stylis@4.3.2: resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} + superagent@8.1.2: + resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==} + engines: {node: '>=6.4.0 <13 || >=14'} + deprecated: Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -6273,6 +6423,9 @@ packages: '@swc/wasm': optional: true + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -6737,6 +6890,10 @@ packages: wildcard-match@5.1.3: resolution: {integrity: sha512-a95hPUk+BNzSGLntNXYxsjz2Hooi5oL7xOfJR6CKwSsSALh7vUNuTlzsrZowtYy38JNduYFRVhFv19ocqNOZlg==} + windows-release@4.0.0: + resolution: {integrity: sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==} + engines: {node: '>=10'} + windows-release@5.1.1: resolution: {integrity: sha512-NMD00arvqcq2nwqc5Q6KtrSRHK+fVD31erE5FEMahAw5PmVCgD7MUXodq3pdZSUkqA9Cda2iWx6s1XYwiJWRmw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -8673,6 +8830,66 @@ snapshots: transitivePeerDependencies: - supports-color + '@ionic/cli-framework-prompts@2.1.13': + dependencies: + '@ionic/utils-terminal': 2.3.5 + debug: 4.3.4(supports-color@8.1.1) + inquirer: 7.3.3 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + + '@ionic/cli-framework@6.0.1': + dependencies: + '@ionic/cli-framework-output': 2.2.8 + '@ionic/utils-array': 2.1.6 + '@ionic/utils-fs': 3.1.7 + '@ionic/utils-object': 2.1.6 + '@ionic/utils-process': 2.1.12 + '@ionic/utils-stream': 3.1.7 + '@ionic/utils-subprocess': 3.0.1 + '@ionic/utils-terminal': 2.3.5 + chalk: 4.1.2 + debug: 4.3.4(supports-color@8.1.1) + lodash: 4.17.21 + minimist: 1.2.8 + rimraf: 3.0.2 + tslib: 2.6.2 + write-file-atomic: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@ionic/cli@7.2.0': + dependencies: + '@ionic/cli-framework': 6.0.1 + '@ionic/cli-framework-output': 2.2.8 + '@ionic/cli-framework-prompts': 2.1.13 + '@ionic/utils-array': 2.1.6 + '@ionic/utils-fs': 3.1.7 + '@ionic/utils-network': 2.1.7 + '@ionic/utils-process': 2.1.12 + '@ionic/utils-stream': 3.1.7 + '@ionic/utils-subprocess': 3.0.1 + '@ionic/utils-terminal': 2.3.5 + chalk: 4.1.2 + debug: 4.3.4(supports-color@8.1.1) + diff: 4.0.2 + elementtree: 0.1.7 + leek: 0.0.24 + lodash: 4.17.21 + open: 7.4.2 + os-name: 4.0.1 + proxy-agent: 6.4.0 + semver: 7.6.0 + split2: 3.2.2 + ssh-config: 1.1.6 + stream-combiner2: 1.1.1 + superagent: 8.1.2 + tar: 6.2.1 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + '@ionic/react-router@8.1.0(react-dom@18.3.1(react@18.3.1))(react-router-dom@5.3.4(react@18.3.1))(react-router@5.3.4(react@18.3.1))(react@18.3.1)': dependencies: '@ionic/react': 8.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -8722,6 +8939,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@ionic/utils-network@2.1.7': + dependencies: + debug: 4.3.4(supports-color@8.1.1) + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + '@ionic/utils-object@2.1.5': dependencies: debug: 4.3.4(supports-color@8.1.1) @@ -8783,6 +9007,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@ionic/utils-stream@3.1.7': + dependencies: + debug: 4.3.4(supports-color@8.1.1) + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + '@ionic/utils-subprocess@2.1.11': dependencies: '@ionic/utils-array': 2.1.5 @@ -8809,6 +9040,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@ionic/utils-subprocess@3.0.1': + dependencies: + '@ionic/utils-array': 2.1.6 + '@ionic/utils-fs': 3.1.7 + '@ionic/utils-process': 2.1.12 + '@ionic/utils-stream': 3.1.7 + '@ionic/utils-terminal': 2.3.5 + cross-spawn: 7.0.3 + debug: 4.3.4(supports-color@8.1.1) + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + '@ionic/utils-terminal@2.3.3': dependencies: '@types/slice-ansi': 4.0.0 @@ -10486,6 +10730,8 @@ snapshots: cli-spinners@2.9.2: {} + cli-width@3.0.0: {} + cli-width@4.1.0: {} cliui@6.0.0: @@ -10555,6 +10801,8 @@ snapshots: compare-versions@6.1.0: {} + component-emitter@1.3.1: {} + concat-map@0.0.1: {} condense-newlines@0.2.1: @@ -10681,6 +10929,8 @@ snapshots: convert-source-map@2.0.0: {} + cookiejar@2.1.4: {} + core-js-compat@3.37.0: dependencies: browserslist: 4.23.0 @@ -10985,6 +11235,10 @@ snapshots: dependencies: is-obj: 2.0.0 + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + eastasianwidth@0.2.0: {} editorconfig@1.0.4: @@ -11297,6 +11551,18 @@ snapshots: esutils@2.0.3: {} + execa@4.1.0: + dependencies: + cross-spawn: 7.0.3 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + execa@5.1.1: dependencies: cross-spawn: 7.0.3 @@ -11371,6 +11637,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-safe-stringify@2.1.1: {} + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -11388,6 +11656,10 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 + figures@3.2.0: + dependencies: + escape-string-regexp: 1.0.5 + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -11453,6 +11725,13 @@ snapshots: dependencies: fetch-blob: 3.2.0 + formidable@2.1.2: + dependencies: + dezalgo: 1.0.4 + hexoid: 1.0.0 + once: 1.4.0 + qs: 6.12.1 + formidable@3.5.1: dependencies: dezalgo: 1.0.4 @@ -11980,6 +12259,8 @@ snapshots: transitivePeerDependencies: - supports-color + human-signals@1.1.1: {} + human-signals@2.1.0: {} human-signals@5.0.0: {} @@ -12030,6 +12311,22 @@ snapshots: inline-style-parser@0.2.3: {} + inquirer@7.3.3: + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + run-async: 2.4.1 + rxjs: 6.6.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + inquirer@9.2.19: dependencies: '@inquirer/figures': 1.0.1 @@ -12483,6 +12780,14 @@ snapshots: dependencies: package-json: 8.1.1 + leek@0.0.24: + dependencies: + debug: 2.6.9 + lodash.assign: 3.2.0 + rsvp: 3.6.2 + transitivePeerDependencies: + - supports-color + lemmy-js-client@0.19.4-alpha.18: {} leven@3.1.0: {} @@ -12534,12 +12839,41 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash._baseassign@3.2.0: + dependencies: + lodash._basecopy: 3.0.1 + lodash.keys: 3.1.2 + + lodash._basecopy@3.0.1: {} + + lodash._bindcallback@3.0.1: {} + + lodash._createassigner@3.1.1: + dependencies: + lodash._bindcallback: 3.0.1 + lodash._isiterateecall: 3.0.9 + lodash.restparam: 3.6.1 + + lodash._getnative@3.9.1: {} + + lodash._isiterateecall@3.0.9: {} + + lodash.assign@3.2.0: + dependencies: + lodash._baseassign: 3.2.0 + lodash._createassigner: 3.1.1 + lodash.keys: 3.1.2 + lodash.capitalize@4.2.1: {} lodash.debounce@4.0.8: {} lodash.escaperegexp@4.1.2: {} + lodash.isarguments@3.1.0: {} + + lodash.isarray@3.0.4: {} + lodash.isequal@4.5.0: {} lodash.ismatch@4.4.0: {} @@ -12548,8 +12882,16 @@ snapshots: lodash.isstring@4.0.1: {} + lodash.keys@3.1.2: + dependencies: + lodash._getnative: 3.9.1 + lodash.isarguments: 3.1.0 + lodash.isarray: 3.0.4 + lodash.merge@4.6.2: {} + lodash.restparam@3.6.1: {} + lodash.sortby@4.7.0: {} lodash.uniqby@4.7.0: {} @@ -12604,6 +12946,8 @@ snapshots: lz-string@1.5.0: {} + macos-release@2.5.1: {} + macos-release@3.2.0: {} magic-string@0.25.9: @@ -12842,6 +13186,8 @@ snapshots: formidable: 3.5.1 xpath: 0.0.27 + methods@1.1.2: {} + micromark-core-commonmark@2.0.0: dependencies: decode-named-character-reference: 1.0.2 @@ -13054,6 +13400,8 @@ snapshots: dependencies: mime-db: 1.52.0 + mime@2.6.0: {} + mimic-fn@2.1.0: {} mimic-fn@4.0.0: {} @@ -13132,6 +13480,8 @@ snapshots: ms@2.1.3: {} + mute-stream@0.0.8: {} + mute-stream@1.0.0: {} nanoid@3.3.7: {} @@ -13321,6 +13671,11 @@ snapshots: is-inside-container: 1.0.0 is-wsl: 3.1.0 + open@7.4.2: + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 @@ -13360,6 +13715,11 @@ snapshots: string-width: 7.1.0 strip-ansi: 7.1.0 + os-name@4.0.1: + dependencies: + macos-release: 2.5.1 + windows-release: 4.0.0 + os-name@5.1.0: dependencies: macos-release: 3.2.0 @@ -13707,6 +14067,10 @@ snapshots: q@1.5.1: {} + qs@6.12.1: + dependencies: + side-channel: 1.0.6 + querystringify@2.2.0: {} queue-microtask@1.2.3: {} @@ -14164,14 +14528,22 @@ snapshots: rrweb-cssom@0.6.0: {} + rsvp@3.6.2: {} + run-applescript@7.0.0: {} + run-async@2.4.1: {} + run-async@3.0.0: {} run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rxjs@6.6.7: + dependencies: + tslib: 1.14.1 + rxjs@7.8.1: dependencies: tslib: 2.6.2 @@ -14382,6 +14754,8 @@ snapshots: sprintf-js@1.1.3: {} + ssh-config@1.1.6: {} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -14398,6 +14772,11 @@ snapshots: stream-buffers@2.2.0: {} + stream-combiner2@1.1.1: + dependencies: + duplexer2: 0.1.4 + readable-stream: 2.3.8 + streamx@2.16.1: dependencies: fast-fifo: 1.3.2 @@ -14510,6 +14889,21 @@ snapshots: stylis@4.3.2: {} + superagent@8.1.2: + dependencies: + component-emitter: 1.3.1 + cookiejar: 2.1.4 + debug: 4.3.4(supports-color@8.1.1) + fast-safe-stringify: 2.1.1 + form-data: 4.0.0 + formidable: 2.1.2 + methods: 1.1.2 + mime: 2.6.0 + qs: 6.12.1 + semver: 7.6.0 + transitivePeerDependencies: + - supports-color + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -14696,6 +15090,8 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + tslib@1.14.1: {} + tslib@2.6.2: {} tunnel-agent@0.6.0: @@ -15200,6 +15596,10 @@ snapshots: wildcard-match@5.1.3: {} + windows-release@4.0.0: + dependencies: + execa: 4.1.0 + windows-release@5.1.1: dependencies: execa: 5.1.1 From 5b44f012f5db57a9e525382c99198d6d5a51c21b Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Thu, 9 May 2024 19:25:04 -0500 Subject: [PATCH 08/11] (chore) Remove unused tsconfig.node.json (#1469) --- Dockerfile | 2 +- tsconfig.json | 3 +-- tsconfig.node.json | 9 --------- 3 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 tsconfig.node.json diff --git a/Dockerfile b/Dockerfile index b90f0b7c2..956285fff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,7 +26,7 @@ COPY patches ./patches RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --ignore-scripts # Copy all source files -COPY build.sh disable_in_app_purchases.sh index.html vite.config.ts manifest.json tsconfig.json tsconfig.node.json ./ +COPY build.sh disable_in_app_purchases.sh index.html vite.config.ts manifest.json tsconfig.json ./ COPY public ./public COPY src ./src diff --git a/tsconfig.json b/tsconfig.json index 78cfa1a50..269ab3e73 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,5 @@ "types": ["vite-plugin-svgr/client", "jest"], "noUncheckedIndexedAccess": true }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src"] } diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 9d31e2aed..000000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} From 6a9860ac25aeba6522caf90b5b9a030177c115de Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Thu, 9 May 2024 19:32:39 -0500 Subject: [PATCH 09/11] Release 2.9.0 --- android/app/build.gradle | 4 ++-- ios/App/App/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 007ffc9a2..9a9b898d3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "app.vger.voyager" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 244 - versionName "2.8.1" + versionCode 245 + versionName "2.9.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/ios/App/App/Info.plist b/ios/App/App/Info.plist index 09b1ec7b5..e2ae4ea9b 100644 --- a/ios/App/App/Info.plist +++ b/ios/App/App/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.8.1 + 2.9.0 CFBundleURLTypes @@ -32,7 +32,7 @@ CFBundleVersion - 244 + 245 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/package.json b/package.json index a9410ee87..dec23151c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "voyager", "description": "A progressive webapp Lemmy client", "private": true, - "version": "2.8.1", + "version": "2.9.0", "type": "module", "packageManager": "pnpm@9.0.6+sha256.0624e30eff866cdeb363b15061bdb7fd9425b17bc1bb42c22f5f4efdea21f6b3", "scripts": { From 2d46158f2bfc49fdb156e43533bc54cbcf887219 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Thu, 9 May 2024 22:47:30 -0500 Subject: [PATCH 10/11] Fix DB failure causing post page to fail to load (#1470) --- src/features/feed/sort/useFeedSort.tsx | 39 +++++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/features/feed/sort/useFeedSort.tsx b/src/features/feed/sort/useFeedSort.tsx index 7a53d7af6..3f0d6e094 100644 --- a/src/features/feed/sort/useFeedSort.tsx +++ b/src/features/feed/sort/useFeedSort.tsx @@ -1,5 +1,5 @@ import { CommentSortType, SortType } from "lemmy-js-client"; -import { useEffect, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useAppDispatch, useAppSelector } from "../../../store"; import { FeedSortFeed, @@ -19,9 +19,11 @@ export default function useSortByFeed( }[Context]; const dispatch = useAppDispatch(); - const feedSort = useAppSelector( - getFeedSortSelectorBuilder(feed, context), - ) as Sort; + + const feedSort = useAppSelector(getFeedSortSelectorBuilder(feed, context)) as + | Sort + | null + | undefined; const defaultSort = useAppSelector( (state) => state.settings.general[context].sort, ) as Sort; @@ -39,7 +41,7 @@ export default function useSortByFeed( if (!feed) return; try { - await dispatch(getFeedSort({ feed, context })); + await dispatch(getFeedSort({ feed, context })).unwrap(); // unwrap to catch dispatched error (db failure) } catch (error) { _setSort((_sort) => _sort ?? defaultSort); // fallback if indexeddb unavailable throw error; @@ -55,19 +57,22 @@ export default function useSortByFeed( _setSort(feedSort ?? defaultSort); }, [feedSort, sort, defaultSort, rememberCommunitySort]); - function setSort(sort: Sort) { - if (rememberCommunitySort && feed) { - dispatch( - setFeedSort({ - feed, - sort, - context, - } as SetSortActionPayload), - ); - } + const setSort = useCallback( + (sort: Sort) => { + if (rememberCommunitySort && feed) { + dispatch( + setFeedSort({ + feed, + sort, + context, + } as SetSortActionPayload), + ); + } - return _setSort(sort); - } + return _setSort(sort); + }, + [context, dispatch, feed, rememberCommunitySort], + ); return [sort, setSort] as const; } From beed4518e5e18d883a3ffd4f1ca1025485430485 Mon Sep 17 00:00:00 2001 From: Alexander Harding <2166114+aeharding@users.noreply.github.com> Date: Thu, 9 May 2024 22:54:50 -0500 Subject: [PATCH 11/11] Release 2.9.1 --- android/app/build.gradle | 4 ++-- ios/App/App/Info.plist | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 9a9b898d3..3cb647aa3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "app.vger.voyager" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 245 - versionName "2.9.0" + versionCode 246 + versionName "2.9.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/ios/App/App/Info.plist b/ios/App/App/Info.plist index e2ae4ea9b..33272ec7b 100644 --- a/ios/App/App/Info.plist +++ b/ios/App/App/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.9.0 + 2.9.1 CFBundleURLTypes @@ -32,7 +32,7 @@ CFBundleVersion - 245 + 246 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/package.json b/package.json index dec23151c..431eb921a 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "voyager", "description": "A progressive webapp Lemmy client", "private": true, - "version": "2.9.0", + "version": "2.9.1", "type": "module", "packageManager": "pnpm@9.0.6+sha256.0624e30eff866cdeb363b15061bdb7fd9425b17bc1bb42c22f5f4efdea21f6b3", "scripts": {