From: Dessalines Date: Thu, 20 Aug 2020 14:50:26 +0000 (-0400) Subject: Switch front end to use lemmy-js-client. Fixes #1090 (#1097) X-Git-Url: http://these/git/%7B%60%24%7BwebArchiveUrl%7D/%22%7B%7D/%22https:/nerdica.net/static/%7Bpost.url%7D?a=commitdiff_plain;h=2080534744f6a2c7d760ea066c17ab4337d7e3d0;p=lemmy.git Switch front end to use lemmy-js-client. Fixes #1090 (#1097) * Switch front end to use lemmy-js-client. Fixes #1090 * Adding an HTTP client. Cleaning up Websocket client. --- diff --git a/README.md b/README.md index 8aa5fe38..57b3d63e 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ Each Lemmy server can set its own moderation policy; appointing site-wide admins ### Libraries +- [lemmy-js-client](https://github.com/LemmyNet/lemmy-js-client) - [Kotlin API ( under development )](https://github.com/eiknat/lemmy-client) ## Support / Donate diff --git a/server/src/routes/api.rs b/server/src/routes/api.rs index 1c88ffa2..20190862 100644 --- a/server/src/routes/api.rs +++ b/server/src/routes/api.rs @@ -94,7 +94,8 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { web::post().to(route_post::), ) .route("/like", web::post().to(route_post::)) - .route("/save", web::put().to(route_post::)), + .route("/save", web::put().to(route_post::)) + .route("/list", web::get().to(route_get::)), ) // Private Message .service( @@ -136,6 +137,7 @@ pub fn config(cfg: &mut web::ServiceConfig, rate_limit: &RateLimit) { "/followed_communities", web::get().to(route_get::), ) + .route("/join", web::post().to(route_post::)) // Admin action. I don't like that it's in /user .route("/ban", web::post().to(route_post::)) // Account actions. I don't like that they're in /user maybe /accounts diff --git a/ui/package.json b/ui/package.json index 06c52807..74740b76 100644 --- a/ui/package.json +++ b/ui/package.json @@ -37,6 +37,7 @@ "inferno-router": "^7.4.2", "js-cookie": "^2.2.0", "jwt-decode": "^2.2.0", + "lemmy-js-client": "^1.0.8", "markdown-it": "^11.0.0", "markdown-it-container": "^3.0.0", "markdown-it-emoji": "^1.4.0", diff --git a/ui/src/api_tests/comment.spec.ts b/ui/src/api_tests/comment.spec.ts index 24aca55f..747ec910 100644 --- a/ui/src/api_tests/comment.spec.ts +++ b/ui/src/api_tests/comment.spec.ts @@ -21,7 +21,7 @@ import { API, } from './shared'; -import { PostResponse } from '../interfaces'; +import { PostResponse } from 'lemmy-js-client'; let postRes: PostResponse; @@ -136,7 +136,7 @@ test('Remove a comment from admin and community on the same instance', async () test('Remove a comment from admin and community on different instance', async () => { let alphaUser = await registerUser(alpha); let newAlphaApi: API = { - url: alpha.url, + client: alpha.client, auth: alphaUser.jwt, }; diff --git a/ui/src/api_tests/shared.ts b/ui/src/api_tests/shared.ts index 29aaff25..710671c0 100644 --- a/ui/src/api_tests/shared.ts +++ b/ui/src/api_tests/shared.ts @@ -1,5 +1,3 @@ -import fetch from 'node-fetch'; - import { LoginForm, LoginResponse, @@ -20,15 +18,21 @@ import { CommentForm, DeleteCommentForm, RemoveCommentForm, + SearchForm, CommentResponse, CommunityForm, DeleteCommunityForm, RemoveCommunityForm, + GetUserMentionsForm, CommentLikeForm, CreatePostLikeForm, PrivateMessageForm, EditPrivateMessageForm, DeletePrivateMessageForm, + GetFollowedCommunitiesForm, + GetPrivateMessagesForm, + GetSiteForm, + GetPostForm, PrivateMessageResponse, PrivateMessagesResponse, GetUserMentionsResponse, @@ -36,35 +40,33 @@ import { SortType, ListingType, GetSiteResponse, -} from '../interfaces'; + SearchType, + LemmyHttp, +} from 'lemmy-js-client'; export interface API { - url: string; + client: LemmyHttp; auth?: string; } -function apiUrl(api: API) { - return `${api.url}/api/v1`; -} - export let alpha: API = { - url: 'http://localhost:8540', + client: new LemmyHttp('http://localhost:8540/api/v1'), }; export let beta: API = { - url: 'http://localhost:8550', + client: new LemmyHttp('http://localhost:8550/api/v1'), }; export let gamma: API = { - url: 'http://localhost:8560', + client: new LemmyHttp('http://localhost:8560/api/v1'), }; export let delta: API = { - url: 'http://localhost:8570', + client: new LemmyHttp('http://localhost:8570/api/v1'), }; export let epsilon: API = { - url: 'http://localhost:8580', + client: new LemmyHttp('http://localhost:8580/api/v1'), }; export async function setupLogins() { @@ -72,69 +74,31 @@ export async function setupLogins() { username_or_email: 'lemmy_alpha', password: 'lemmy', }; - - let resAlpha: Promise = fetch(`${apiUrl(alpha)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formAlpha), - }).then(d => d.json()); + let resAlpha = alpha.client.login(formAlpha); let formBeta = { username_or_email: 'lemmy_beta', password: 'lemmy', }; - - let resBeta: Promise = fetch(`${apiUrl(beta)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formBeta), - }).then(d => d.json()); + let resBeta = beta.client.login(formBeta); let formGamma = { username_or_email: 'lemmy_gamma', password: 'lemmy', }; - - let resGamma: Promise = fetch(`${apiUrl(gamma)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formGamma), - }).then(d => d.json()); + let resGamma = gamma.client.login(formGamma); let formDelta = { username_or_email: 'lemmy_delta', password: 'lemmy', }; - - let resDelta: Promise = fetch(`${apiUrl(delta)}/user/login`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formDelta), - }).then(d => d.json()); + let resDelta = delta.client.login(formDelta); let formEpsilon = { username_or_email: 'lemmy_epsilon', password: 'lemmy', }; - - let resEpsilon: Promise = fetch( - `${apiUrl(epsilon)}/user/login`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(formEpsilon), - } - ).then(d => d.json()); + let resEpsilon = epsilon.client.login(formEpsilon); let res = await Promise.all([ resAlpha, @@ -156,40 +120,24 @@ export async function createPost( community_id: number ): Promise { let name = 'A jest test post'; - let postForm: PostForm = { + let form: PostForm = { name, auth: api.auth, community_id, nsfw: false, }; - - let createPostRes: PostResponse = await fetch(`${apiUrl(api)}/post`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(postForm), - }).then(d => d.json()); - return createPostRes; + return api.client.createPost(form); } export async function updatePost(api: API, post: Post): Promise { let name = 'A jest test federated post, updated'; - let postForm: PostForm = { + let form: PostForm = { name, edit_id: post.id, auth: api.auth, nsfw: false, }; - - let updateResponse: PostResponse = await fetch(`${apiUrl(api)}/post`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(postForm), - }).then(d => d.json()); - return updateResponse; + return api.client.editPost(form); } export async function deletePost( @@ -197,20 +145,12 @@ export async function deletePost( deleted: boolean, post: Post ): Promise { - let deletePostForm: DeletePostForm = { + let form: DeletePostForm = { edit_id: post.id, deleted: deleted, auth: api.auth, }; - - let deletePostRes: PostResponse = await fetch(`${apiUrl(api)}/post/delete`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deletePostForm), - }).then(d => d.json()); - return deletePostRes; + return api.client.deletePost(form); } export async function removePost( @@ -218,20 +158,12 @@ export async function removePost( removed: boolean, post: Post ): Promise { - let removePostForm: RemovePostForm = { + let form: RemovePostForm = { edit_id: post.id, removed, auth: api.auth, }; - - let removePostRes: PostResponse = await fetch(`${apiUrl(api)}/post/remove`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(removePostForm), - }).then(d => d.json()); - return removePostRes; + return api.client.removePost(form); } export async function stickyPost( @@ -239,21 +171,12 @@ export async function stickyPost( stickied: boolean, post: Post ): Promise { - let stickyPostForm: StickyPostForm = { + let form: StickyPostForm = { edit_id: post.id, stickied, auth: api.auth, }; - - let stickyRes: PostResponse = await fetch(`${apiUrl(api)}/post/sticky`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(stickyPostForm), - }).then(d => d.json()); - - return stickyRes; + return api.client.stickyPost(form); } export async function lockPost( @@ -261,57 +184,46 @@ export async function lockPost( locked: boolean, post: Post ): Promise { - let lockPostForm: LockPostForm = { + let form: LockPostForm = { edit_id: post.id, locked, auth: api.auth, }; - - let lockRes: PostResponse = await fetch(`${apiUrl(api)}/post/lock`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(lockPostForm), - }).then(d => d.json()); - - return lockRes; + return api.client.lockPost(form); } export async function searchPost( api: API, post: Post ): Promise { - let searchUrl = `${apiUrl(api)}/search?q=${post.ap_id}&type_=All&sort=TopAll`; - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: post.ap_id, + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function getPost( api: API, post_id: number ): Promise { - let getPostUrl = `${apiUrl(api)}/post?id=${post_id}`; - let getPostRes: GetPostResponse = await fetch(getPostUrl, { - method: 'GET', - }).then(d => d.json()); - - return getPostRes; + let form: GetPostForm = { + id: post_id, + }; + return api.client.getPost(form); } export async function searchComment( api: API, comment: Comment ): Promise { - let searchUrl = `${apiUrl(api)}/search?q=${ - comment.ap_id - }&type_=All&sort=TopAll`; - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: comment.ap_id, + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function searchForBetaCommunity( @@ -319,14 +231,12 @@ export async function searchForBetaCommunity( ): Promise { // Make sure lemmy-beta/c/main is cached on lemmy_alpha // Use short-hand search url - let searchUrl = `${apiUrl( - api - )}/search?q=!main@lemmy-beta:8550&type_=All&sort=TopAll`; - - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: '!main@lemmy-beta:8550', + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function searchForUser( @@ -335,14 +245,12 @@ export async function searchForUser( ): Promise { // Make sure lemmy-beta/c/main is cached on lemmy_alpha // Use short-hand search url - let searchUrl = `${apiUrl( - api - )}/search?q=${apShortname}&type_=All&sort=TopAll`; - - let searchResponse: SearchResponse = await fetch(searchUrl, { - method: 'GET', - }).then(d => d.json()); - return searchResponse; + let form: SearchForm = { + q: apShortname, + type_: SearchType.All, + sort: SortType.TopAll, + }; + return api.client.search(form); } export async function followCommunity( @@ -350,41 +258,21 @@ export async function followCommunity( follow: boolean, community_id: number ): Promise { - let followForm: FollowCommunityForm = { + let form: FollowCommunityForm = { community_id, follow, auth: api.auth, }; - - let followRes: CommunityResponse = await fetch( - `${apiUrl(api)}/community/follow`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(followForm), - } - ) - .then(d => d.json()) - .catch(_e => {}); - - return followRes; + return api.client.followCommunity(form); } export async function checkFollowedCommunities( api: API ): Promise { - let followedCommunitiesUrl = `${apiUrl( - api - )}/user/followed_communities?&auth=${api.auth}`; - let followedCommunitiesRes: GetFollowedCommunitiesResponse = await fetch( - followedCommunitiesUrl, - { - method: 'GET', - } - ).then(d => d.json()); - return followedCommunitiesRes; + let form: GetFollowedCommunitiesForm = { + auth: api.auth, + }; + return api.client.getFollowedCommunities(form); } export async function likePost( @@ -392,21 +280,13 @@ export async function likePost( score: number, post: Post ): Promise { - let likePostForm: CreatePostLikeForm = { + let form: CreatePostLikeForm = { post_id: post.id, score: score, auth: api.auth, }; - let likePostRes: PostResponse = await fetch(`${apiUrl(api)}/post/like`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(likePostForm), - }).then(d => d.json()); - - return likePostRes; + return api.client.likePost(form); } export async function createComment( @@ -415,21 +295,13 @@ export async function createComment( parent_id?: number, content = 'a jest test comment' ): Promise { - let commentForm: CommentForm = { + let form: CommentForm = { content, post_id, parent_id, auth: api.auth, }; - - let createResponse: CommentResponse = await fetch(`${apiUrl(api)}/comment`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(commentForm), - }).then(d => d.json()); - return createResponse; + return api.client.createComment(form); } export async function updateComment( @@ -437,20 +309,12 @@ export async function updateComment( edit_id: number, content = 'A jest test federated comment update' ): Promise { - let commentForm: CommentForm = { + let form: CommentForm = { content, edit_id, auth: api.auth, }; - - let updateResponse: CommentResponse = await fetch(`${apiUrl(api)}/comment`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(commentForm), - }).then(d => d.json()); - return updateResponse; + return api.client.editComment(form); } export async function deleteComment( @@ -458,23 +322,12 @@ export async function deleteComment( deleted: boolean, edit_id: number ): Promise { - let deleteCommentForm: DeleteCommentForm = { + let form: DeleteCommentForm = { edit_id, deleted, auth: api.auth, }; - - let deleteCommentRes: CommentResponse = await fetch( - `${apiUrl(api)}/comment/delete`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deleteCommentForm), - } - ).then(d => d.json()); - return deleteCommentRes; + return api.client.deleteComment(form); } export async function removeComment( @@ -482,33 +335,21 @@ export async function removeComment( removed: boolean, edit_id: number ): Promise { - let removeCommentForm: RemoveCommentForm = { + let form: RemoveCommentForm = { edit_id, removed, auth: api.auth, }; - - let removeCommentRes: CommentResponse = await fetch( - `${apiUrl(api)}/comment/remove`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(removeCommentForm), - } - ).then(d => d.json()); - return removeCommentRes; + return api.client.removeComment(form); } export async function getMentions(api: API): Promise { - let getMentionUrl = `${apiUrl( - api - )}/user/mention?sort=New&unread_only=false&auth=${api.auth}`; - let getMentionsRes: GetUserMentionsResponse = await fetch(getMentionUrl, { - method: 'GET', - }).then(d => d.json()); - return getMentionsRes; + let form: GetUserMentionsForm = { + sort: SortType.New, + unread_only: false, + auth: api.auth, + }; + return api.client.getUserMentions(form); } export async function likeComment( @@ -516,48 +357,26 @@ export async function likeComment( score: number, comment: Comment ): Promise { - let likeCommentForm: CommentLikeForm = { + let form: CommentLikeForm = { comment_id: comment.id, score, auth: api.auth, }; - - let likeCommentRes: CommentResponse = await fetch( - `${apiUrl(api)}/comment/like`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(likeCommentForm), - } - ).then(d => d.json()); - return likeCommentRes; + return api.client.likeComment(form); } export async function createCommunity( api: API, name_: string = randomString(5) ): Promise { - let communityForm: CommunityForm = { + let form: CommunityForm = { name: name_, title: name_, category_id: 1, nsfw: false, auth: api.auth, }; - - let createCommunityRes: CommunityResponse = await fetch( - `${apiUrl(api)}/community`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(communityForm), - } - ).then(d => d.json()); - return createCommunityRes; + return api.client.createCommunity(form); } export async function deleteCommunity( @@ -565,23 +384,12 @@ export async function deleteCommunity( deleted: boolean, edit_id: number ): Promise { - let deleteCommunityForm: DeleteCommunityForm = { + let form: DeleteCommunityForm = { edit_id, deleted, auth: api.auth, }; - - let deleteResponse: CommunityResponse = await fetch( - `${apiUrl(api)}/community/delete`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deleteCommunityForm), - } - ).then(d => d.json()); - return deleteResponse; + return api.client.deleteCommunity(form); } export async function removeCommunity( @@ -589,23 +397,12 @@ export async function removeCommunity( removed: boolean, edit_id: number ): Promise { - let removeCommunityForm: RemoveCommunityForm = { + let form: RemoveCommunityForm = { edit_id, removed, auth: api.auth, }; - - let removeResponse: CommunityResponse = await fetch( - `${apiUrl(api)}/community/remove`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(removeCommunityForm), - } - ).then(d => d.json()); - return removeResponse; + return api.client.removeCommunity(form); } export async function createPrivateMessage( @@ -613,23 +410,12 @@ export async function createPrivateMessage( recipient_id: number ): Promise { let content = 'A jest test federated private message'; - let privateMessageForm: PrivateMessageForm = { + let form: PrivateMessageForm = { content, recipient_id, auth: api.auth, }; - - let createRes: PrivateMessageResponse = await fetch( - `${apiUrl(api)}/private_message`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(privateMessageForm), - } - ).then(d => d.json()); - return createRes; + return api.client.createPrivateMessage(form); } export async function updatePrivateMessage( @@ -637,23 +423,12 @@ export async function updatePrivateMessage( edit_id: number ): Promise { let updatedContent = 'A jest test federated private message edited'; - let updatePrivateMessageForm: EditPrivateMessageForm = { + let form: EditPrivateMessageForm = { content: updatedContent, edit_id, auth: api.auth, }; - - let updateRes: PrivateMessageResponse = await fetch( - `${apiUrl(api)}/private_message`, - { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(updatePrivateMessageForm), - } - ).then(d => d.json()); - return updateRes; + return api.client.editPrivateMessage(form); } export async function deletePrivateMessage( @@ -661,50 +436,26 @@ export async function deletePrivateMessage( deleted: boolean, edit_id: number ): Promise { - let deletePrivateMessageForm: DeletePrivateMessageForm = { + let form: DeletePrivateMessageForm = { deleted, edit_id, auth: api.auth, }; - - let deleteRes: PrivateMessageResponse = await fetch( - `${apiUrl(api)}/private_message/delete`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(deletePrivateMessageForm), - } - ).then(d => d.json()); - - return deleteRes; + return api.client.deletePrivateMessage(form); } export async function registerUser( api: API, username: string = randomString(5) ): Promise { - let registerForm: RegisterForm = { + let form: RegisterForm = { username, password: 'test', password_verify: 'test', admin: false, show_nsfw: true, }; - - let registerRes: Promise = fetch( - `${apiUrl(api)}/user/register`, - { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(registerForm), - } - ).then(d => d.json()); - - return registerRes; + return api.client.register(form); } export async function saveUserSettingsBio( @@ -714,54 +465,36 @@ export async function saveUserSettingsBio( let form: UserSettingsForm = { show_nsfw: true, theme: 'darkly', - default_sort_type: SortType.Active, - default_listing_type: ListingType.All, + default_sort_type: Object.keys(SortType).indexOf(SortType.Active), + default_listing_type: Object.keys(ListingType).indexOf(ListingType.All), lang: 'en', show_avatars: true, send_notifications_to_email: false, bio: 'a changed bio', auth, }; - - let res: Promise = fetch( - `${apiUrl(api)}/user/save_user_settings`, - { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: wrapper(form), - } - ).then(d => d.json()); - return res; + return api.client.saveUserSettings(form); } export async function getSite( api: API, auth: string ): Promise { - let siteUrl = `${apiUrl(api)}/site?auth=${auth}`; - - let res: GetSiteResponse = await fetch(siteUrl, { - method: 'GET', - }).then(d => d.json()); - return res; + let form: GetSiteForm = { + auth, + }; + return api.client.getSite(form); } export async function listPrivateMessages( api: API ): Promise { - let getPrivateMessagesUrl = `${apiUrl(api)}/private_message/list?auth=${ - api.auth - }&unread_only=false&limit=999`; - - let getPrivateMessagesRes: PrivateMessagesResponse = await fetch( - getPrivateMessagesUrl, - { - method: 'GET', - } - ).then(d => d.json()); - return getPrivateMessagesRes; + let form: GetPrivateMessagesForm = { + auth: api.auth, + unread_only: false, + limit: 999, + }; + return api.client.getPrivateMessages(form); } export async function unfollowRemotes( diff --git a/ui/src/components/admin-settings.tsx b/ui/src/components/admin-settings.tsx index fe50b1e9..a3bfdd81 100644 --- a/ui/src/components/admin-settings.tsx +++ b/ui/src/components/admin-settings.tsx @@ -9,7 +9,7 @@ import { SiteConfigForm, GetSiteConfigResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, capitalizeFirstLetter, toast, randomStr } from '../utils'; import autosize from 'autosize'; diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 5597f58e..dbd14dc7 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -8,7 +8,7 @@ import { WebSocketJsonResponse, UserOperation, CommentResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { capitalizeFirstLetter, wsJsonToRes } from '../utils'; import { WebSocketService, UserService } from '../services'; import { i18n } from '../i18next'; diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index 13263b82..1992c4fc 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -16,10 +16,9 @@ import { AddAdminForm, TransferCommunityForm, TransferSiteForm, - BanType, - CommentSortType, SortType, -} from '../interfaces'; +} from 'lemmy-js-client'; +import { CommentSortType, BanType } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, diff --git a/ui/src/components/comment-nodes.tsx b/ui/src/components/comment-nodes.tsx index 62693f76..bdb8a545 100644 --- a/ui/src/components/comment-nodes.tsx +++ b/ui/src/components/comment-nodes.tsx @@ -1,11 +1,11 @@ import { Component } from 'inferno'; +import { CommentSortType } from '../interfaces'; import { CommentNode as CommentNodeI, CommunityUser, UserView, - CommentSortType, SortType, -} from '../interfaces'; +} from 'lemmy-js-client'; import { commentSort, commentSortSortType } from '../utils'; import { CommentNode } from './comment-node'; diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index 038e4517..5be032c5 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -13,7 +13,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, toast, getPageFromProps } from '../utils'; import { CommunityLink } from './community-link'; @@ -218,7 +218,7 @@ export class Communities extends Component { refetch() { let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.TopAll], + sort: SortType.TopAll, limit: communityLimit, page: this.state.page, }; diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index 1ae96ac8..7b8c379b 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -9,12 +9,12 @@ import { ListCategoriesResponse, CommunityResponse, WebSocketJsonResponse, -} from '../interfaces'; + Community, +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, capitalizeFirstLetter, toast, randomStr } from '../utils'; import { i18n } from '../i18next'; -import { Community } from '../interfaces'; import { MarkdownTextArea } from './markdown-textarea'; import { ImageUploadForm } from './image-upload-form'; diff --git a/ui/src/components/community-link.tsx b/ui/src/components/community-link.tsx index 293ded04..003f61e1 100644 --- a/ui/src/components/community-link.tsx +++ b/ui/src/components/community-link.tsx @@ -1,6 +1,6 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; -import { Community } from '../interfaces'; +import { Community } from 'lemmy-js-client'; import { hostname, pictrsAvatarThumbnail, showAvatars } from '../utils'; interface CommunityOther { diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 1fe75c59..f86562f8 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -2,6 +2,7 @@ import { Component, linkEvent } from 'inferno'; import { Helmet } from 'inferno-helmet'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; +import { DataType } from '../interfaces'; import { UserOperation, Community as CommunityI, @@ -14,7 +15,6 @@ import { GetPostsForm, GetCommunityForm, ListingType, - DataType, GetPostsResponse, PostResponse, AddModToCommunityResponse, @@ -26,7 +26,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { PostListings } from './post-listings'; import { CommentNodes } from './comment-nodes'; @@ -78,7 +78,7 @@ interface CommunityProps { interface UrlParams { dataType?: string; - sort?: string; + sort?: SortType; page?: number; } @@ -287,9 +287,7 @@ export class Community extends Component { { } handleSortChange(val: SortType) { - this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); + this.updateUrl({ sort: val, page: 1 }); window.scrollTo(0, 0); } handleDataTypeChange(val: DataType) { - this.updateUrl({ dataType: DataType[val].toLowerCase(), page: 1 }); + this.updateUrl({ dataType: DataType[val], page: 1 }); window.scrollTo(0, 0); } updateUrl(paramUpdates: UrlParams) { - const dataTypeStr = - paramUpdates.dataType || DataType[this.state.dataType].toLowerCase(); - const sortStr = - paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const dataTypeStr = paramUpdates.dataType || DataType[this.state.dataType]; + const sortStr = paramUpdates.sort || this.state.sort; const page = paramUpdates.page || this.state.page; this.props.history.push( `/c/${this.state.community.name}/data_type/${dataTypeStr}/sort/${sortStr}/page/${page}` @@ -361,8 +357,8 @@ export class Community extends Component { let getPostsForm: GetPostsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[ListingType.Community], + sort: this.state.sort, + type_: ListingType.Community, community_id: this.state.community.id, }; WebSocketService.Instance.getPosts(getPostsForm); @@ -370,8 +366,8 @@ export class Community extends Component { let getCommentsForm: GetCommentsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[ListingType.Community], + sort: this.state.sort, + type_: ListingType.Community, community_id: this.state.community.id, }; WebSocketService.Instance.getComments(getCommentsForm); diff --git a/ui/src/components/create-community.tsx b/ui/src/components/create-community.tsx index 8317ffbe..6f156211 100644 --- a/ui/src/components/create-community.tsx +++ b/ui/src/components/create-community.tsx @@ -9,7 +9,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { toast, wsJsonToRes } from '../utils'; import { WebSocketService, UserService } from '../services'; import { i18n } from '../i18next'; diff --git a/ui/src/components/create-post.tsx b/ui/src/components/create-post.tsx index eb86d8f8..f4c03b65 100644 --- a/ui/src/components/create-post.tsx +++ b/ui/src/components/create-post.tsx @@ -11,7 +11,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { i18n } from '../i18next'; interface CreatePostState { diff --git a/ui/src/components/create-private-message.tsx b/ui/src/components/create-private-message.tsx index ed06a66a..98c69d5b 100644 --- a/ui/src/components/create-private-message.tsx +++ b/ui/src/components/create-private-message.tsx @@ -10,7 +10,7 @@ import { GetSiteResponse, Site, PrivateMessageFormParams, -} from '../interfaces'; +} from 'lemmy-js-client'; import { toast, wsJsonToRes } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/footer.tsx b/ui/src/components/footer.tsx index 6e7acb7a..62585ff3 100644 --- a/ui/src/components/footer.tsx +++ b/ui/src/components/footer.tsx @@ -9,7 +9,7 @@ import { UserOperation, WebSocketJsonResponse, GetSiteResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; interface FooterState { version: string; diff --git a/ui/src/components/iframely-card.tsx b/ui/src/components/iframely-card.tsx index 1a47f377..6a604f7c 100644 --- a/ui/src/components/iframely-card.tsx +++ b/ui/src/components/iframely-card.tsx @@ -1,5 +1,5 @@ import { Component, linkEvent } from 'inferno'; -import { Post } from '../interfaces'; +import { Post } from 'lemmy-js-client'; import { mdToHtml } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx index ecc9223c..4da86e35 100644 --- a/ui/src/components/inbox.tsx +++ b/ui/src/components/inbox.tsx @@ -19,7 +19,7 @@ import { PrivateMessageResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, @@ -399,7 +399,7 @@ export class Inbox extends Component { refetch() { let repliesForm: GetRepliesForm = { - sort: SortType[this.state.sort], + sort: this.state.sort, unread_only: this.state.unreadOrAll == UnreadOrAll.Unread, page: this.state.page, limit: fetchLimit, @@ -407,7 +407,7 @@ export class Inbox extends Component { WebSocketService.Instance.getReplies(repliesForm); let userMentionsForm: GetUserMentionsForm = { - sort: SortType[this.state.sort], + sort: this.state.sort, unread_only: this.state.unreadOrAll == UnreadOrAll.Unread, page: this.state.page, limit: fetchLimit, diff --git a/ui/src/components/instances.tsx b/ui/src/components/instances.tsx index ae4e3f13..bcc02480 100644 --- a/ui/src/components/instances.tsx +++ b/ui/src/components/instances.tsx @@ -6,7 +6,7 @@ import { UserOperation, WebSocketJsonResponse, GetSiteResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, toast } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/listing-type-select.tsx b/ui/src/components/listing-type-select.tsx index 6bdf457c..3d12d434 100644 --- a/ui/src/components/listing-type-select.tsx +++ b/ui/src/components/listing-type-select.tsx @@ -1,7 +1,7 @@ import { Component, linkEvent } from 'inferno'; -import { ListingType } from '../interfaces'; +import { ListingType } from 'lemmy-js-client'; import { UserService } from '../services'; - +import { randomStr } from '../utils'; import { i18n } from '../i18next'; interface ListingTypeSelectProps { @@ -17,6 +17,8 @@ export class ListingTypeSelect extends Component< ListingTypeSelectProps, ListingTypeSelectState > { + private id = `listing-type-input-${randomStr()}`; + private emptyState: ListingTypeSelectState = { type_: this.props.type_, }; @@ -42,6 +44,7 @@ export class ListingTypeSelect extends Component< `} > { } let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.Hot], + sort: SortType.Hot, limit: 6, }; @@ -334,13 +334,9 @@ export class Main extends Component { } updateUrl(paramUpdates: UrlParams) { - const listingTypeStr = - paramUpdates.listingType || - ListingType[this.state.listingType].toLowerCase(); - const dataTypeStr = - paramUpdates.dataType || DataType[this.state.dataType].toLowerCase(); - const sortStr = - paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const listingTypeStr = paramUpdates.listingType || this.state.listingType; + const dataTypeStr = paramUpdates.dataType || DataType[this.state.dataType]; + const sortStr = paramUpdates.sort || this.state.sort; const page = paramUpdates.page || this.state.page; this.props.history.push( `/home/data_type/${dataTypeStr}/listing_type/${listingTypeStr}/sort/${sortStr}/page/${page}` @@ -549,7 +545,7 @@ export class Main extends Component { {this.state.listingType == ListingType.All && ( { {UserService.Instance.user && this.state.listingType == ListingType.Subscribed && ( { } handleSortChange(val: SortType) { - this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); + this.updateUrl({ sort: val, page: 1 }); window.scrollTo(0, 0); } handleListingTypeChange(val: ListingType) { - this.updateUrl({ listingType: ListingType[val].toLowerCase(), page: 1 }); + this.updateUrl({ listingType: val, page: 1 }); window.scrollTo(0, 0); } handleDataTypeChange(val: DataType) { - this.updateUrl({ dataType: DataType[val].toLowerCase(), page: 1 }); + this.updateUrl({ dataType: DataType[val], page: 1 }); window.scrollTo(0, 0); } @@ -650,16 +644,16 @@ export class Main extends Component { let getPostsForm: GetPostsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[this.state.listingType], + sort: this.state.sort, + type_: this.state.listingType, }; WebSocketService.Instance.getPosts(getPostsForm); } else { let getCommentsForm: GetCommentsForm = { page: this.state.page, limit: fetchLimit, - sort: SortType[this.state.sort], - type_: ListingType[this.state.listingType], + sort: this.state.sort, + type_: this.state.listingType, }; WebSocketService.Instance.getComments(getCommentsForm); } diff --git a/ui/src/components/modlog.tsx b/ui/src/components/modlog.tsx index 0cc78da7..106015a4 100644 --- a/ui/src/components/modlog.tsx +++ b/ui/src/components/modlog.tsx @@ -19,7 +19,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, addTypeInfo, fetchLimit, toast } from '../utils'; import { MomentTime } from './moment-time'; diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 0ddcbb4c..4ef5276c 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -18,7 +18,7 @@ import { PrivateMessage, PrivateMessageResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { wsJsonToRes, pictrsAvatarThumbnail, @@ -137,7 +137,7 @@ export class Navbar extends Component { this.context.router.history.push(`/search/`); } else { this.context.router.history.push( - `/search/q/${searchParam}/type/all/sort/topall/page/1` + `/search/q/${searchParam}/type/All/sort/TopAll/page/1` ); } } @@ -477,14 +477,14 @@ export class Navbar extends Component { fetchUnreads() { console.log('Fetching unreads...'); let repliesForm: GetRepliesForm = { - sort: SortType[SortType.New], + sort: SortType.New, unread_only: true, page: 1, limit: fetchLimit, }; let userMentionsForm: GetUserMentionsForm = { - sort: SortType[SortType.New], + sort: SortType.New, unread_only: true, page: 1, limit: fetchLimit, diff --git a/ui/src/components/password_change.tsx b/ui/src/components/password_change.tsx index 5b157f7f..527f21e0 100644 --- a/ui/src/components/password_change.tsx +++ b/ui/src/components/password_change.tsx @@ -9,7 +9,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, capitalizeFirstLetter, toast } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index 854cff6e..97b44f5f 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -18,7 +18,7 @@ import { SearchType, SearchResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, @@ -121,7 +121,7 @@ export class PostForm extends Component { ); let listCommunitiesForm: ListCommunitiesForm = { - sort: SortType[SortType.TopAll], + sort: SortType.TopAll, limit: 9999, }; @@ -405,8 +405,8 @@ export class PostForm extends Component { if (validURL(this.state.postForm.url)) { let form: SearchForm = { q: this.state.postForm.url, - type_: SearchType[SearchType.Url], - sort: SortType[SortType.TopAll], + type_: SearchType.Url, + sort: SortType.TopAll, page: 1, limit: 6, }; @@ -433,8 +433,8 @@ export class PostForm extends Component { fetchSimilarPosts() { let form: SearchForm = { q: this.state.postForm.name, - type_: SearchType[SearchType.Posts], - sort: SortType[SortType.TopAll], + type_: SearchType.Posts, + sort: SortType.TopAll, community_id: this.state.postForm.community_id, page: 1, limit: 6, diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index e3e19e99..fa4bf391 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -11,14 +11,14 @@ import { SavePostForm, CommunityUser, UserView, - BanType, BanFromCommunityForm, BanUserForm, AddModToCommunityForm, AddAdminForm, TransferSiteForm, TransferCommunityForm, -} from '../interfaces'; +} from 'lemmy-js-client'; +import { BanType } from '../interfaces'; import { MomentTime } from './moment-time'; import { PostForm } from './post-form'; import { IFramelyCard } from './iframely-card'; diff --git a/ui/src/components/post-listings.tsx b/ui/src/components/post-listings.tsx index cd65d934..2c9b4a88 100644 --- a/ui/src/components/post-listings.tsx +++ b/ui/src/components/post-listings.tsx @@ -1,6 +1,6 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; -import { Post, SortType } from '../interfaces'; +import { Post, SortType } from 'lemmy-js-client'; import { postSort } from '../utils'; import { PostListing } from './post-listing'; import { i18n } from '../i18next'; diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 06f461f3..e9427a5e 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -11,8 +11,6 @@ import { Comment, MarkCommentAsReadForm, CommentResponse, - CommentSortType, - CommentViewType, CommunityUser, CommunityResponse, CommentNode as CommentNodeI, @@ -28,7 +26,8 @@ import { GetSiteResponse, GetCommunityResponse, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; +import { CommentSortType, CommentViewType } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, @@ -439,8 +438,8 @@ export class Post extends Component { if (this.state.post.url) { let form: SearchForm = { q: this.state.post.url, - type_: SearchType[SearchType.Url], - sort: SortType[SortType.TopAll], + type_: SearchType.Url, + sort: SortType.TopAll, page: 1, limit: 6, }; diff --git a/ui/src/components/private-message-form.tsx b/ui/src/components/private-message-form.tsx index ff889c24..6d7825cd 100644 --- a/ui/src/components/private-message-form.tsx +++ b/ui/src/components/private-message-form.tsx @@ -14,7 +14,7 @@ import { GetUserDetailsForm, SortType, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { capitalizeFirstLetter, @@ -77,7 +77,7 @@ export class PrivateMessageForm extends Component< this.state.privateMessageForm.recipient_id = this.props.params.recipient_id; let form: GetUserDetailsForm = { user_id: this.state.privateMessageForm.recipient_id, - sort: SortType[SortType.New], + sort: SortType.New, saved_only: false, }; WebSocketService.Instance.getUserDetails(form); diff --git a/ui/src/components/private-message.tsx b/ui/src/components/private-message.tsx index bb6aca4c..243d12e5 100644 --- a/ui/src/components/private-message.tsx +++ b/ui/src/components/private-message.tsx @@ -4,7 +4,7 @@ import { PrivateMessage as PrivateMessageI, DeletePrivateMessageForm, MarkPrivateMessageAsReadForm, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, pictrsAvatarThumbnail, showAvatars, toast } from '../utils'; import { MomentTime } from './moment-time'; diff --git a/ui/src/components/search.tsx b/ui/src/components/search.tsx index fc19cab9..a18cc2d8 100644 --- a/ui/src/components/search.tsx +++ b/ui/src/components/search.tsx @@ -17,7 +17,7 @@ import { WebSocketJsonResponse, GetSiteResponse, Site, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { wsJsonToRes, @@ -57,8 +57,8 @@ interface SearchProps { interface UrlParams { q?: string; - type_?: string; - sort?: string; + type_?: SearchType; + sort?: SortType; page?: number; } @@ -461,8 +461,8 @@ export class Search extends Component { search() { let form: SearchForm = { q: this.state.q, - type_: SearchType[this.state.type_], - sort: SortType[this.state.sort], + type_: this.state.type_, + sort: this.state.sort, page: this.state.page, limit: fetchLimit, }; @@ -473,12 +473,12 @@ export class Search extends Component { } handleSortChange(val: SortType) { - this.updateUrl({ sort: SortType[val].toLowerCase(), page: 1 }); + this.updateUrl({ sort: val, page: 1 }); } handleTypeChange(i: Search, event: any) { i.updateUrl({ - type_: SearchType[Number(event.target.value)].toLowerCase(), + type_: SearchType[event.target.value], page: 1, }); } @@ -487,8 +487,8 @@ export class Search extends Component { event.preventDefault(); i.updateUrl({ q: i.state.searchText, - type_: SearchType[i.state.type_].toLowerCase(), - sort: SortType[i.state.sort].toLowerCase(), + type_: i.state.type_, + sort: i.state.sort, page: i.state.page, }); } @@ -499,10 +499,8 @@ export class Search extends Component { updateUrl(paramUpdates: UrlParams) { const qStr = paramUpdates.q || this.state.q; - const typeStr = - paramUpdates.type_ || SearchType[this.state.type_].toLowerCase(); - const sortStr = - paramUpdates.sort || SortType[this.state.sort].toLowerCase(); + const typeStr = paramUpdates.type_ || this.state.type_; + const sortStr = paramUpdates.sort || this.state.sort; const page = paramUpdates.page || this.state.page; this.props.history.push( `/search/q/${qStr}/type/${typeStr}/sort/${sortStr}/page/${page}` diff --git a/ui/src/components/setup.tsx b/ui/src/components/setup.tsx index 7da14379..6360ec5a 100644 --- a/ui/src/components/setup.tsx +++ b/ui/src/components/setup.tsx @@ -7,7 +7,7 @@ import { LoginResponse, UserOperation, WebSocketJsonResponse, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { wsJsonToRes, toast } from '../utils'; import { SiteForm } from './site-form'; diff --git a/ui/src/components/sidebar.tsx b/ui/src/components/sidebar.tsx index b434bb87..25cbd797 100644 --- a/ui/src/components/sidebar.tsx +++ b/ui/src/components/sidebar.tsx @@ -8,7 +8,7 @@ import { RemoveCommunityForm, UserView, AddModToCommunityForm, -} from '../interfaces'; +} from 'lemmy-js-client'; import { WebSocketService, UserService } from '../services'; import { mdToHtml, getUnixTime } from '../utils'; import { CommunityForm } from './community-form'; diff --git a/ui/src/components/site-form.tsx b/ui/src/components/site-form.tsx index 98f1259b..9b572f57 100644 --- a/ui/src/components/site-form.tsx +++ b/ui/src/components/site-form.tsx @@ -2,7 +2,7 @@ import { Component, linkEvent } from 'inferno'; import { Prompt } from 'inferno-router'; import { MarkdownTextArea } from './markdown-textarea'; import { ImageUploadForm } from './image-upload-form'; -import { Site, SiteForm as SiteFormI } from '../interfaces'; +import { Site, SiteForm as SiteFormI } from 'lemmy-js-client'; import { WebSocketService } from '../services'; import { capitalizeFirstLetter, randomStr } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/sort-select.tsx b/ui/src/components/sort-select.tsx index 778ed65c..1f0fb055 100644 --- a/ui/src/components/sort-select.tsx +++ b/ui/src/components/sort-select.tsx @@ -1,6 +1,6 @@ import { Component, linkEvent } from 'inferno'; -import { SortType } from '../interfaces'; -import { sortingHelpUrl } from '../utils'; +import { SortType } from 'lemmy-js-client'; +import { sortingHelpUrl, randomStr } from '../utils'; import { i18n } from '../i18next'; interface SortSelectProps { @@ -14,6 +14,7 @@ interface SortSelectState { } export class SortSelect extends Component { + private id = `sort-select-${randomStr()}`; private emptyState: SortSelectState = { sort: this.props.sort, }; @@ -33,6 +34,8 @@ export class SortSelect extends Component { return ( <>