mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-26 19:31:05 +00:00
Merge branch 'dev'
This commit is contained in:
commit
088f47c611
29 changed files with 379 additions and 262 deletions
16
README.md
vendored
16
README.md
vendored
|
@ -202,14 +202,14 @@ If you'd like to add translations, take a look a look at the [English translatio
|
||||||
|
|
||||||
lang | done | missing
|
lang | done | missing
|
||||||
--- | --- | ---
|
--- | --- | ---
|
||||||
de | 82% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,subscribed,expires,recent_comments,nsfw,show_nsfw,theme,crypto,monero,joined,by,to,transfer_community,transfer_site,are_you_sure,yes,no
|
de | 81% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,subscribed,replies,mentions,expires,recent_comments,nsfw,show_nsfw,theme,crypto,monero,joined,by,to,transfer_community,transfer_site,are_you_sure,yes,no
|
||||||
eo | 91% | number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,theme,are_you_sure,yes,no
|
eo | 90% | number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,theme,are_you_sure,yes,no
|
||||||
es | 100% |
|
es | 99% | replies,mentions
|
||||||
fr | 100% |
|
fr | 99% | replies,mentions
|
||||||
nl | 93% | preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,theme
|
nl | 92% | preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,theme
|
||||||
ru | 86% | cross_posts,cross_post,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,recent_comments,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
|
ru | 86% | cross_posts,cross_post,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,recent_comments,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
|
||||||
sv | 100% |
|
sv | 99% | replies,mentions
|
||||||
zh | 84% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,recent_comments,nsfw,show_nsfw,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
|
zh | 83% | cross_posts,cross_post,users,number_of_communities,preview,upload_image,formatting_help,view_source,sticky,unsticky,settings,stickied,delete_account,delete_account_confirm,banned,creator,number_online,replies,mentions,recent_comments,nsfw,show_nsfw,theme,monero,by,to,transfer_community,transfer_site,are_you_sure,yes,no
|
||||||
|
|
||||||
If you'd like to update this report, run:
|
If you'd like to update this report, run:
|
||||||
|
|
||||||
|
|
2
server/migrations/2019-10-21-011237_add_default_sorts/down.sql
vendored
Normal file
2
server/migrations/2019-10-21-011237_add_default_sorts/down.sql
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
alter table user_ drop column default_sort_type;
|
||||||
|
alter table user_ drop column default_listing_type;
|
2
server/migrations/2019-10-21-011237_add_default_sorts/up.sql
vendored
Normal file
2
server/migrations/2019-10-21-011237_add_default_sorts/up.sql
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
alter table user_ add column default_sort_type smallint default 0 not null;
|
||||||
|
alter table user_ add column default_listing_type smallint default 1 not null;
|
|
@ -235,7 +235,7 @@ impl Perform<GetPostsResponse> for Oper<GetPosts> {
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_ = PostListingType::from_str(&data.type_)?;
|
let type_ = ListingType::from_str(&data.type_)?;
|
||||||
let sort = SortType::from_str(&data.sort)?;
|
let sort = SortType::from_str(&data.sort)?;
|
||||||
|
|
||||||
let posts = match PostView::list(
|
let posts = match PostView::list(
|
||||||
|
|
|
@ -321,7 +321,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
||||||
SearchType::Posts => {
|
SearchType::Posts => {
|
||||||
posts = PostView::list(
|
posts = PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::All,
|
ListingType::All,
|
||||||
&sort,
|
&sort,
|
||||||
data.community_id,
|
data.community_id,
|
||||||
None,
|
None,
|
||||||
|
@ -365,7 +365,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
||||||
SearchType::All => {
|
SearchType::All => {
|
||||||
posts = PostView::list(
|
posts = PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::All,
|
ListingType::All,
|
||||||
&sort,
|
&sort,
|
||||||
data.community_id,
|
data.community_id,
|
||||||
None,
|
None,
|
||||||
|
@ -403,7 +403,7 @@ impl Perform<SearchResponse> for Oper<Search> {
|
||||||
SearchType::Url => {
|
SearchType::Url => {
|
||||||
posts = PostView::list(
|
posts = PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::All,
|
ListingType::All,
|
||||||
&sort,
|
&sort,
|
||||||
data.community_id,
|
data.community_id,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -22,6 +22,8 @@ pub struct Register {
|
||||||
pub struct SaveUserSettings {
|
pub struct SaveUserSettings {
|
||||||
show_nsfw: bool,
|
show_nsfw: bool,
|
||||||
theme: String,
|
theme: String,
|
||||||
|
default_sort_type: i16,
|
||||||
|
default_listing_type: i16,
|
||||||
auth: String,
|
auth: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +200,8 @@ impl Perform<LoginResponse> for Oper<Register> {
|
||||||
banned: false,
|
banned: false,
|
||||||
show_nsfw: data.show_nsfw,
|
show_nsfw: data.show_nsfw,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create the user
|
// Create the user
|
||||||
|
@ -289,6 +293,8 @@ impl Perform<LoginResponse> for Oper<SaveUserSettings> {
|
||||||
banned: read_user.banned,
|
banned: read_user.banned,
|
||||||
show_nsfw: data.show_nsfw,
|
show_nsfw: data.show_nsfw,
|
||||||
theme: data.theme.to_owned(),
|
theme: data.theme.to_owned(),
|
||||||
|
default_sort_type: data.default_sort_type,
|
||||||
|
default_listing_type: data.default_listing_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
let updated_user = match User_::update(&conn, user_id, &user_form) {
|
let updated_user = match User_::update(&conn, user_id, &user_form) {
|
||||||
|
@ -346,7 +352,7 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
||||||
let posts = if data.saved_only {
|
let posts = if data.saved_only {
|
||||||
PostView::list(
|
PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::All,
|
ListingType::All,
|
||||||
&sort,
|
&sort,
|
||||||
data.community_id,
|
data.community_id,
|
||||||
None,
|
None,
|
||||||
|
@ -362,7 +368,7 @@ impl Perform<GetUserDetailsResponse> for Oper<GetUserDetails> {
|
||||||
} else {
|
} else {
|
||||||
PostView::list(
|
PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::All,
|
ListingType::All,
|
||||||
&sort,
|
&sort,
|
||||||
data.community_id,
|
data.community_id,
|
||||||
Some(user_details_id),
|
Some(user_details_id),
|
||||||
|
@ -453,6 +459,8 @@ impl Perform<AddAdminResponse> for Oper<AddAdmin> {
|
||||||
banned: read_user.banned,
|
banned: read_user.banned,
|
||||||
show_nsfw: read_user.show_nsfw,
|
show_nsfw: read_user.show_nsfw,
|
||||||
theme: read_user.theme,
|
theme: read_user.theme,
|
||||||
|
default_sort_type: read_user.default_sort_type,
|
||||||
|
default_listing_type: read_user.default_listing_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
match User_::update(&conn, data.user_id, &user_form) {
|
match User_::update(&conn, data.user_id, &user_form) {
|
||||||
|
@ -512,6 +520,8 @@ impl Perform<BanUserResponse> for Oper<BanUser> {
|
||||||
banned: data.ban,
|
banned: data.ban,
|
||||||
show_nsfw: read_user.show_nsfw,
|
show_nsfw: read_user.show_nsfw,
|
||||||
theme: read_user.theme,
|
theme: read_user.theme,
|
||||||
|
default_sort_type: read_user.default_sort_type,
|
||||||
|
default_listing_type: read_user.default_listing_type,
|
||||||
};
|
};
|
||||||
|
|
||||||
match User_::update(&conn, data.user_id, &user_form) {
|
match User_::update(&conn, data.user_id, &user_form) {
|
||||||
|
@ -751,7 +761,7 @@ impl Perform<LoginResponse> for Oper<DeleteAccount> {
|
||||||
// Posts
|
// Posts
|
||||||
let posts = PostView::list(
|
let posts = PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::All,
|
ListingType::All,
|
||||||
&SortType::New,
|
&SortType::New,
|
||||||
None,
|
None,
|
||||||
Some(user_id),
|
Some(user_id),
|
||||||
|
|
|
@ -55,6 +55,7 @@ impl User_ {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::User_;
|
use super::User_;
|
||||||
|
use crate::db::{ListingType, SortType};
|
||||||
use crate::naive_now;
|
use crate::naive_now;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -73,6 +74,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let person = expected_user.person();
|
let person = expected_user.person();
|
||||||
|
|
|
@ -179,6 +179,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
|
|
@ -264,6 +264,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
|
|
@ -265,6 +265,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
|
|
@ -106,6 +106,13 @@ pub enum SortType {
|
||||||
TopAll,
|
TopAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum ListingType {
|
||||||
|
All,
|
||||||
|
Subscribed,
|
||||||
|
Community,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
|
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
|
||||||
pub enum SearchType {
|
pub enum SearchType {
|
||||||
All,
|
All,
|
||||||
|
|
|
@ -447,6 +447,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_mod = User_::create(&conn, &new_mod).unwrap();
|
let inserted_mod = User_::create(&conn, &new_mod).unwrap();
|
||||||
|
@ -462,6 +464,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
|
|
@ -192,6 +192,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
|
|
@ -1,12 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum PostListingType {
|
|
||||||
All,
|
|
||||||
Subscribed,
|
|
||||||
Community,
|
|
||||||
}
|
|
||||||
|
|
||||||
// The faked schema since diesel doesn't do views
|
// The faked schema since diesel doesn't do views
|
||||||
table! {
|
table! {
|
||||||
post_view (id) {
|
post_view (id) {
|
||||||
|
@ -83,7 +76,7 @@ pub struct PostView {
|
||||||
impl PostView {
|
impl PostView {
|
||||||
pub fn list(
|
pub fn list(
|
||||||
conn: &PgConnection,
|
conn: &PgConnection,
|
||||||
type_: PostListingType,
|
type_: ListingType,
|
||||||
sort: &SortType,
|
sort: &SortType,
|
||||||
for_community_id: Option<i32>,
|
for_community_id: Option<i32>,
|
||||||
for_creator_id: Option<i32>,
|
for_creator_id: Option<i32>,
|
||||||
|
@ -129,7 +122,7 @@ impl PostView {
|
||||||
};
|
};
|
||||||
|
|
||||||
match type_ {
|
match type_ {
|
||||||
PostListingType::Subscribed => {
|
ListingType::Subscribed => {
|
||||||
query = query.filter(subscribed.eq(true));
|
query = query.filter(subscribed.eq(true));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -226,6 +219,8 @@ mod tests {
|
||||||
banned: false,
|
banned: false,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
@ -351,7 +346,7 @@ mod tests {
|
||||||
|
|
||||||
let read_post_listings_with_user = PostView::list(
|
let read_post_listings_with_user = PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::Community,
|
ListingType::Community,
|
||||||
&SortType::New,
|
&SortType::New,
|
||||||
Some(inserted_community.id),
|
Some(inserted_community.id),
|
||||||
None,
|
None,
|
||||||
|
@ -367,7 +362,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let read_post_listings_no_user = PostView::list(
|
let read_post_listings_no_user = PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::Community,
|
ListingType::Community,
|
||||||
&SortType::New,
|
&SortType::New,
|
||||||
Some(inserted_community.id),
|
Some(inserted_community.id),
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -21,6 +21,8 @@ pub struct User_ {
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
pub show_nsfw: bool,
|
pub show_nsfw: bool,
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
|
pub default_sort_type: i16,
|
||||||
|
pub default_listing_type: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, AsChangeset, Clone)]
|
#[derive(Insertable, AsChangeset, Clone)]
|
||||||
|
@ -36,6 +38,8 @@ pub struct UserForm {
|
||||||
pub updated: Option<chrono::NaiveDateTime>,
|
pub updated: Option<chrono::NaiveDateTime>,
|
||||||
pub show_nsfw: bool,
|
pub show_nsfw: bool,
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
|
pub default_sort_type: i16,
|
||||||
|
pub default_listing_type: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Crud<UserForm> for User_ {
|
impl Crud<UserForm> for User_ {
|
||||||
|
@ -77,6 +81,8 @@ pub struct Claims {
|
||||||
pub iss: String,
|
pub iss: String,
|
||||||
pub show_nsfw: bool,
|
pub show_nsfw: bool,
|
||||||
pub theme: String,
|
pub theme: String,
|
||||||
|
pub default_sort_type: i16,
|
||||||
|
pub default_listing_type: i16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Claims {
|
impl Claims {
|
||||||
|
@ -98,6 +104,8 @@ impl User_ {
|
||||||
iss: self.fedi_name.to_owned(),
|
iss: self.fedi_name.to_owned(),
|
||||||
show_nsfw: self.show_nsfw,
|
show_nsfw: self.show_nsfw,
|
||||||
theme: self.theme.to_owned(),
|
theme: self.theme.to_owned(),
|
||||||
|
default_sort_type: self.default_sort_type,
|
||||||
|
default_listing_type: self.default_listing_type,
|
||||||
};
|
};
|
||||||
encode(
|
encode(
|
||||||
&Header::default(),
|
&Header::default(),
|
||||||
|
@ -146,6 +154,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
@ -164,6 +174,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_user = User_::read(&conn, inserted_user.id).unwrap();
|
let read_user = User_::read(&conn, inserted_user.id).unwrap();
|
||||||
|
|
|
@ -73,6 +73,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
let inserted_user = User_::create(&conn, &new_user).unwrap();
|
||||||
|
@ -88,6 +90,8 @@ mod tests {
|
||||||
updated: None,
|
updated: None,
|
||||||
show_nsfw: false,
|
show_nsfw: false,
|
||||||
theme: "darkly".into(),
|
theme: "darkly".into(),
|
||||||
|
default_sort_type: SortType::Hot as i16,
|
||||||
|
default_listing_type: ListingType::Subscribed as i16,
|
||||||
};
|
};
|
||||||
|
|
||||||
let inserted_recipient = User_::create(&conn, &recipient_form).unwrap();
|
let inserted_recipient = User_::create(&conn, &recipient_form).unwrap();
|
||||||
|
|
|
@ -255,6 +255,8 @@ table! {
|
||||||
updated -> Nullable<Timestamp>,
|
updated -> Nullable<Timestamp>,
|
||||||
show_nsfw -> Bool,
|
show_nsfw -> Bool,
|
||||||
theme -> Varchar,
|
theme -> Varchar,
|
||||||
|
default_sort_type -> Int2,
|
||||||
|
default_listing_type -> Int2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ impl ChatServer {
|
||||||
let conn = establish_connection();
|
let conn = establish_connection();
|
||||||
let posts = PostView::list(
|
let posts = PostView::list(
|
||||||
&conn,
|
&conn,
|
||||||
PostListingType::Community,
|
ListingType::Community,
|
||||||
&SortType::New,
|
&SortType::New,
|
||||||
Some(*community_id),
|
Some(*community_id),
|
||||||
None,
|
None,
|
||||||
|
|
19
ui/package.json
vendored
19
ui/package.json
vendored
|
@ -22,6 +22,7 @@
|
||||||
"classcat": "^1.1.3",
|
"classcat": "^1.1.3",
|
||||||
"dotenv": "^6.1.0",
|
"dotenv": "^6.1.0",
|
||||||
"emoji-short-name": "^0.1.0",
|
"emoji-short-name": "^0.1.0",
|
||||||
|
"husky": "^3.0.9",
|
||||||
"i18next": "^17.0.9",
|
"i18next": "^17.0.9",
|
||||||
"inferno": "^7.0.1",
|
"inferno": "^7.0.1",
|
||||||
"inferno-i18next": "nimbusec-oss/inferno-i18next",
|
"inferno-i18next": "nimbusec-oss/inferno-i18next",
|
||||||
|
@ -45,7 +46,6 @@
|
||||||
"eslint-plugin-inferno": "^7.14.3",
|
"eslint-plugin-inferno": "^7.14.3",
|
||||||
"eslint-plugin-jane": "^7.0.0",
|
"eslint-plugin-jane": "^7.0.0",
|
||||||
"fuse-box": "^3.1.3",
|
"fuse-box": "^3.1.3",
|
||||||
"husky": "^3.0.9",
|
|
||||||
"lint-staged": "^9.4.2",
|
"lint-staged": "^9.4.2",
|
||||||
"sortpack": "^2.0.1",
|
"sortpack": "^2.0.1",
|
||||||
"ts-transform-classcat": "^0.0.2",
|
"ts-transform-classcat": "^0.0.2",
|
||||||
|
@ -58,24 +58,13 @@
|
||||||
"engineStrict": true,
|
"engineStrict": true,
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "lint-staged",
|
"pre-commit": "lint-staged"
|
||||||
"pre-push": "yarn run lint"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.js": [
|
"*.{ts,tsx,js}": [
|
||||||
"prettier --write",
|
"prettier --write",
|
||||||
"yarn run lint",
|
"eslint --fix",
|
||||||
"git add"
|
|
||||||
],
|
|
||||||
"*.ts": [
|
|
||||||
"prettier --write",
|
|
||||||
"yarn run lint",
|
|
||||||
"git add"
|
|
||||||
],
|
|
||||||
"*.tsx": [
|
|
||||||
"prettier --write",
|
|
||||||
"yarn run lint",
|
|
||||||
"git add"
|
"git add"
|
||||||
],
|
],
|
||||||
"package.json": [
|
"package.json": [
|
||||||
|
|
60
ui/src/components/community.tsx
vendored
60
ui/src/components/community.tsx
vendored
|
@ -15,8 +15,9 @@ import {
|
||||||
GetPostsResponse,
|
GetPostsResponse,
|
||||||
CreatePostLikeResponse,
|
CreatePostLikeResponse,
|
||||||
} from '../interfaces';
|
} from '../interfaces';
|
||||||
import { WebSocketService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { PostListings } from './post-listings';
|
import { PostListings } from './post-listings';
|
||||||
|
import { SortSelect } from './sort-select';
|
||||||
import { Sidebar } from './sidebar';
|
import { Sidebar } from './sidebar';
|
||||||
import {
|
import {
|
||||||
msgOp,
|
msgOp,
|
||||||
|
@ -71,6 +72,8 @@ export class Community extends Component<any, State> {
|
||||||
getSortTypeFromProps(props: any): SortType {
|
getSortTypeFromProps(props: any): SortType {
|
||||||
return props.match.params.sort
|
return props.match.params.sort
|
||||||
? routeSortTypeToEnum(props.match.params.sort)
|
? routeSortTypeToEnum(props.match.params.sort)
|
||||||
|
: UserService.Instance.user
|
||||||
|
? UserService.Instance.user.default_sort_type
|
||||||
: SortType.Hot;
|
: SortType.Hot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +85,7 @@ export class Community extends Component<any, State> {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
|
this.handleSortChange = this.handleSortChange.bind(this);
|
||||||
|
|
||||||
this.subscription = WebSocketService.Instance.subject
|
this.subscription = WebSocketService.Instance.subject
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -112,10 +116,13 @@ export class Community extends Component<any, State> {
|
||||||
|
|
||||||
// Necessary for back button for some reason
|
// Necessary for back button for some reason
|
||||||
componentWillReceiveProps(nextProps: any) {
|
componentWillReceiveProps(nextProps: any) {
|
||||||
if (nextProps.history.action == 'POP') {
|
if (
|
||||||
this.state = this.emptyState;
|
nextProps.history.action == 'POP' ||
|
||||||
|
nextProps.history.action == 'PUSH'
|
||||||
|
) {
|
||||||
this.state.sort = this.getSortTypeFromProps(nextProps);
|
this.state.sort = this.getSortTypeFromProps(nextProps);
|
||||||
this.state.page = this.getPageFromProps(nextProps);
|
this.state.page = this.getPageFromProps(nextProps);
|
||||||
|
this.setState(this.state);
|
||||||
this.fetchPosts();
|
this.fetchPosts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,38 +171,8 @@ export class Community extends Component<any, State> {
|
||||||
|
|
||||||
selects() {
|
selects() {
|
||||||
return (
|
return (
|
||||||
<div className="mb-2">
|
<div class="mb-2">
|
||||||
<select
|
<SortSelect sort={this.state.sort} onChange={this.handleSortChange} />
|
||||||
value={this.state.sort}
|
|
||||||
onChange={linkEvent(this, this.handleSortChange)}
|
|
||||||
class="custom-select custom-select-sm w-auto"
|
|
||||||
>
|
|
||||||
<option disabled>
|
|
||||||
<T i18nKey="sort_type">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.Hot}>
|
|
||||||
<T i18nKey="hot">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.New}>
|
|
||||||
<T i18nKey="new">#</T>
|
|
||||||
</option>
|
|
||||||
<option disabled>──────</option>
|
|
||||||
<option value={SortType.TopDay}>
|
|
||||||
<T i18nKey="top_day">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopWeek}>
|
|
||||||
<T i18nKey="week">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopMonth}>
|
|
||||||
<T i18nKey="month">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopYear}>
|
|
||||||
<T i18nKey="year">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopAll}>
|
|
||||||
<T i18nKey="all">#</T>
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -237,12 +214,13 @@ export class Community extends Component<any, State> {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSortChange(i: Community, event: any) {
|
handleSortChange(val: SortType) {
|
||||||
i.state.sort = Number(event.target.value);
|
this.state.sort = val;
|
||||||
i.state.page = 1;
|
this.state.page = 1;
|
||||||
i.setState(i.state);
|
this.state.loading = true;
|
||||||
i.updateUrl();
|
this.setState(this.state);
|
||||||
i.fetchPosts();
|
this.updateUrl();
|
||||||
|
this.fetchPosts();
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
ui/src/components/inbox.tsx
vendored
44
ui/src/components/inbox.tsx
vendored
|
@ -16,6 +16,7 @@ import {
|
||||||
import { WebSocketService, UserService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { msgOp } from '../utils';
|
import { msgOp } from '../utils';
|
||||||
import { CommentNodes } from './comment-nodes';
|
import { CommentNodes } from './comment-nodes';
|
||||||
|
import { SortSelect } from './sort-select';
|
||||||
import { i18n } from '../i18next';
|
import { i18n } from '../i18next';
|
||||||
import { T } from 'inferno-i18next';
|
import { T } from 'inferno-i18next';
|
||||||
|
|
||||||
|
@ -54,6 +55,7 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
|
this.handleSortChange = this.handleSortChange.bind(this);
|
||||||
|
|
||||||
this.subscription = WebSocketService.Instance.subject
|
this.subscription = WebSocketService.Instance.subject
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -153,33 +155,11 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
<T i18nKey="mentions">#</T>
|
<T i18nKey="mentions">#</T>
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<select
|
<SortSelect
|
||||||
value={this.state.sort}
|
sort={this.state.sort}
|
||||||
onChange={linkEvent(this, this.handleSortChange)}
|
onChange={this.handleSortChange}
|
||||||
class="custom-select custom-select-sm w-auto"
|
hideHot
|
||||||
>
|
/>
|
||||||
<option disabled>
|
|
||||||
<T i18nKey="sort_type">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.New}>
|
|
||||||
<T i18nKey="new">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopDay}>
|
|
||||||
<T i18nKey="top_day">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopWeek}>
|
|
||||||
<T i18nKey="week">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopMonth}>
|
|
||||||
<T i18nKey="month">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopYear}>
|
|
||||||
<T i18nKey="year">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopAll}>
|
|
||||||
<T i18nKey="all">#</T>
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -300,11 +280,11 @@ export class Inbox extends Component<any, InboxState> {
|
||||||
WebSocketService.Instance.getUserMentions(userMentionsForm);
|
WebSocketService.Instance.getUserMentions(userMentionsForm);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSortChange(i: Inbox, event: any) {
|
handleSortChange(val: SortType) {
|
||||||
i.state.sort = Number(event.target.value);
|
this.state.sort = val;
|
||||||
i.state.page = 1;
|
this.state.page = 1;
|
||||||
i.setState(i.state);
|
this.setState(this.state);
|
||||||
i.refetch();
|
this.refetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
markAllAsRead() {
|
markAllAsRead() {
|
||||||
|
|
68
ui/src/components/listing-type-select.tsx
vendored
Normal file
68
ui/src/components/listing-type-select.tsx
vendored
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import { Component, linkEvent } from 'inferno';
|
||||||
|
import { ListingType } from '../interfaces';
|
||||||
|
import { UserService } from '../services';
|
||||||
|
|
||||||
|
import { i18n } from '../i18next';
|
||||||
|
|
||||||
|
interface ListingTypeSelectProps {
|
||||||
|
type_: ListingType;
|
||||||
|
onChange?(val: ListingType): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ListingTypeSelectState {
|
||||||
|
type_: ListingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ListingTypeSelect extends Component<
|
||||||
|
ListingTypeSelectProps,
|
||||||
|
ListingTypeSelectState
|
||||||
|
> {
|
||||||
|
private emptyState: ListingTypeSelectState = {
|
||||||
|
type_: this.props.type_,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
this.state = this.emptyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div class="btn-group btn-group-toggle">
|
||||||
|
<label
|
||||||
|
className={`btn btn-sm btn-secondary
|
||||||
|
${this.state.type_ == ListingType.Subscribed && 'active'}
|
||||||
|
${UserService.Instance.user == undefined ? 'disabled' : 'pointer'}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={ListingType.Subscribed}
|
||||||
|
checked={this.state.type_ == ListingType.Subscribed}
|
||||||
|
onChange={linkEvent(this, this.handleTypeChange)}
|
||||||
|
disabled={UserService.Instance.user == undefined}
|
||||||
|
/>
|
||||||
|
{i18n.t('subscribed')}
|
||||||
|
</label>
|
||||||
|
<label
|
||||||
|
className={`pointer btn btn-sm btn-secondary ${this.state.type_ ==
|
||||||
|
ListingType.All && 'active'}`}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
value={ListingType.All}
|
||||||
|
checked={this.state.type_ == ListingType.All}
|
||||||
|
onChange={linkEvent(this, this.handleTypeChange)}
|
||||||
|
/>
|
||||||
|
{i18n.t('all')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTypeChange(i: ListingTypeSelect, event: any) {
|
||||||
|
i.state.type_ = Number(event.target.value);
|
||||||
|
i.setState(i.state);
|
||||||
|
i.props.onChange(i.state.type_);
|
||||||
|
}
|
||||||
|
}
|
103
ui/src/components/main.tsx
vendored
103
ui/src/components/main.tsx
vendored
|
@ -20,6 +20,8 @@ import {
|
||||||
} from '../interfaces';
|
} from '../interfaces';
|
||||||
import { WebSocketService, UserService } from '../services';
|
import { WebSocketService, UserService } from '../services';
|
||||||
import { PostListings } from './post-listings';
|
import { PostListings } from './post-listings';
|
||||||
|
import { SortSelect } from './sort-select';
|
||||||
|
import { ListingTypeSelect } from './listing-type-select';
|
||||||
import { SiteForm } from './site-form';
|
import { SiteForm } from './site-form';
|
||||||
import {
|
import {
|
||||||
msgOp,
|
msgOp,
|
||||||
|
@ -80,13 +82,15 @@ export class Main extends Component<any, MainState> {
|
||||||
return props.match.params.type
|
return props.match.params.type
|
||||||
? routeListingTypeToEnum(props.match.params.type)
|
? routeListingTypeToEnum(props.match.params.type)
|
||||||
: UserService.Instance.user
|
: UserService.Instance.user
|
||||||
? ListingType.Subscribed
|
? UserService.Instance.user.default_listing_type
|
||||||
: ListingType.All;
|
: ListingType.All;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSortTypeFromProps(props: any): SortType {
|
getSortTypeFromProps(props: any): SortType {
|
||||||
return props.match.params.sort
|
return props.match.params.sort
|
||||||
? routeSortTypeToEnum(props.match.params.sort)
|
? routeSortTypeToEnum(props.match.params.sort)
|
||||||
|
: UserService.Instance.user
|
||||||
|
? UserService.Instance.user.default_sort_type
|
||||||
: SortType.Hot;
|
: SortType.Hot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +103,8 @@ export class Main extends Component<any, MainState> {
|
||||||
|
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
this.handleEditCancel = this.handleEditCancel.bind(this);
|
this.handleEditCancel = this.handleEditCancel.bind(this);
|
||||||
|
this.handleSortChange = this.handleSortChange.bind(this);
|
||||||
|
this.handleTypeChange = this.handleTypeChange.bind(this);
|
||||||
|
|
||||||
this.subscription = WebSocketService.Instance.subject
|
this.subscription = WebSocketService.Instance.subject
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -421,66 +427,13 @@ export class Main extends Component<any, MainState> {
|
||||||
selects() {
|
selects() {
|
||||||
return (
|
return (
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<div class="btn-group btn-group-toggle">
|
<ListingTypeSelect
|
||||||
<label
|
type_={this.state.type_}
|
||||||
className={`btn btn-sm btn-secondary
|
onChange={this.handleTypeChange}
|
||||||
${this.state.type_ == ListingType.Subscribed && 'active'}
|
/>
|
||||||
${UserService.Instance.user == undefined ? 'disabled' : 'pointer'}
|
<span class="ml-2">
|
||||||
`}
|
<SortSelect sort={this.state.sort} onChange={this.handleSortChange} />
|
||||||
>
|
</span>
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
value={ListingType.Subscribed}
|
|
||||||
checked={this.state.type_ == ListingType.Subscribed}
|
|
||||||
onChange={linkEvent(this, this.handleTypeChange)}
|
|
||||||
disabled={UserService.Instance.user == undefined}
|
|
||||||
/>
|
|
||||||
{i18n.t('subscribed')}
|
|
||||||
</label>
|
|
||||||
<label
|
|
||||||
className={`pointer btn btn-sm btn-secondary ${this.state.type_ ==
|
|
||||||
ListingType.All && 'active'}`}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="radio"
|
|
||||||
value={ListingType.All}
|
|
||||||
checked={this.state.type_ == ListingType.All}
|
|
||||||
onChange={linkEvent(this, this.handleTypeChange)}
|
|
||||||
/>
|
|
||||||
{i18n.t('all')}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<select
|
|
||||||
value={this.state.sort}
|
|
||||||
onChange={linkEvent(this, this.handleSortChange)}
|
|
||||||
class="ml-2 custom-select custom-select-sm w-auto"
|
|
||||||
>
|
|
||||||
<option disabled>
|
|
||||||
<T i18nKey="sort_type">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.Hot}>
|
|
||||||
<T i18nKey="hot">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.New}>
|
|
||||||
<T i18nKey="new">#</T>
|
|
||||||
</option>
|
|
||||||
<option disabled>─────</option>
|
|
||||||
<option value={SortType.TopDay}>
|
|
||||||
<T i18nKey="top_day">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopWeek}>
|
|
||||||
<T i18nKey="week">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopMonth}>
|
|
||||||
<T i18nKey="month">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopYear}>
|
|
||||||
<T i18nKey="year">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopAll}>
|
|
||||||
<T i18nKey="all">#</T>
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -543,23 +496,23 @@ export class Main extends Component<any, MainState> {
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSortChange(i: Main, event: any) {
|
handleSortChange(val: SortType) {
|
||||||
i.state.sort = Number(event.target.value);
|
this.state.sort = val;
|
||||||
i.state.page = 1;
|
this.state.page = 1;
|
||||||
i.state.loading = true;
|
this.state.loading = true;
|
||||||
i.setState(i.state);
|
this.setState(this.state);
|
||||||
i.updateUrl();
|
this.updateUrl();
|
||||||
i.fetchPosts();
|
this.fetchPosts();
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTypeChange(i: Main, event: any) {
|
handleTypeChange(val: ListingType) {
|
||||||
i.state.type_ = Number(event.target.value);
|
this.state.type_ = val;
|
||||||
i.state.page = 1;
|
this.state.page = 1;
|
||||||
i.state.loading = true;
|
this.state.loading = true;
|
||||||
i.setState(i.state);
|
this.setState(this.state);
|
||||||
i.updateUrl();
|
this.updateUrl();
|
||||||
i.fetchPosts();
|
this.fetchPosts();
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
46
ui/src/components/search.tsx
vendored
46
ui/src/components/search.tsx
vendored
|
@ -21,6 +21,7 @@ import {
|
||||||
routeSortTypeToEnum,
|
routeSortTypeToEnum,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { PostListing } from './post-listing';
|
import { PostListing } from './post-listing';
|
||||||
|
import { SortSelect } from './sort-select';
|
||||||
import { CommentNodes } from './comment-nodes';
|
import { CommentNodes } from './comment-nodes';
|
||||||
import { i18n } from '../i18next';
|
import { i18n } from '../i18next';
|
||||||
import { T } from 'inferno-i18next';
|
import { T } from 'inferno-i18next';
|
||||||
|
@ -76,6 +77,7 @@ export class Search extends Component<any, SearchState> {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
|
this.handleSortChange = this.handleSortChange.bind(this);
|
||||||
|
|
||||||
this.subscription = WebSocketService.Instance.subject
|
this.subscription = WebSocketService.Instance.subject
|
||||||
.pipe(
|
.pipe(
|
||||||
|
@ -203,33 +205,13 @@ export class Search extends Component<any, SearchState> {
|
||||||
<T i18nKey="users">#</T>
|
<T i18nKey="users">#</T>
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<select
|
<span class="ml-2">
|
||||||
value={this.state.sort}
|
<SortSelect
|
||||||
onChange={linkEvent(this, this.handleSortChange)}
|
sort={this.state.sort}
|
||||||
class="custom-select custom-select-sm w-auto ml-2"
|
onChange={this.handleSortChange}
|
||||||
>
|
hideHot
|
||||||
<option disabled>
|
/>
|
||||||
<T i18nKey="sort_type">#</T>
|
</span>
|
||||||
</option>
|
|
||||||
<option value={SortType.New}>
|
|
||||||
<T i18nKey="new">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopDay}>
|
|
||||||
<T i18nKey="top_day">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopWeek}>
|
|
||||||
<T i18nKey="week">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopMonth}>
|
|
||||||
<T i18nKey="month">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopYear}>
|
|
||||||
<T i18nKey="year">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopAll}>
|
|
||||||
<T i18nKey="all">#</T>
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -438,11 +420,11 @@ export class Search extends Component<any, SearchState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSortChange(i: Search, event: any) {
|
handleSortChange(val: SortType) {
|
||||||
i.state.sort = Number(event.target.value);
|
this.state.sort = val;
|
||||||
i.state.page = 1;
|
this.state.page = 1;
|
||||||
i.setState(i.state);
|
this.setState(this.state);
|
||||||
i.updateUrl();
|
this.updateUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTypeChange(i: Search, event: any) {
|
handleTypeChange(i: Search, event: any) {
|
||||||
|
|
69
ui/src/components/sort-select.tsx
vendored
Normal file
69
ui/src/components/sort-select.tsx
vendored
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import { Component, linkEvent } from 'inferno';
|
||||||
|
import { SortType } from '../interfaces';
|
||||||
|
|
||||||
|
import { T } from 'inferno-i18next';
|
||||||
|
|
||||||
|
interface SortSelectProps {
|
||||||
|
sort: SortType;
|
||||||
|
onChange?(val: SortType): any;
|
||||||
|
hideHot?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SortSelectState {
|
||||||
|
sort: SortType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SortSelect extends Component<SortSelectProps, SortSelectState> {
|
||||||
|
private emptyState: SortSelectState = {
|
||||||
|
sort: this.props.sort,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: any, context: any) {
|
||||||
|
super(props, context);
|
||||||
|
this.state = this.emptyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<select
|
||||||
|
value={this.state.sort}
|
||||||
|
onChange={linkEvent(this, this.handleSortChange)}
|
||||||
|
class="custom-select custom-select-sm w-auto"
|
||||||
|
>
|
||||||
|
<option disabled>
|
||||||
|
<T i18nKey="sort_type">#</T>
|
||||||
|
</option>
|
||||||
|
{!this.props.hideHot && (
|
||||||
|
<option value={SortType.Hot}>
|
||||||
|
<T i18nKey="hot">#</T>
|
||||||
|
</option>
|
||||||
|
)}
|
||||||
|
<option value={SortType.New}>
|
||||||
|
<T i18nKey="new">#</T>
|
||||||
|
</option>
|
||||||
|
<option disabled>─────</option>
|
||||||
|
<option value={SortType.TopDay}>
|
||||||
|
<T i18nKey="top_day">#</T>
|
||||||
|
</option>
|
||||||
|
<option value={SortType.TopWeek}>
|
||||||
|
<T i18nKey="week">#</T>
|
||||||
|
</option>
|
||||||
|
<option value={SortType.TopMonth}>
|
||||||
|
<T i18nKey="month">#</T>
|
||||||
|
</option>
|
||||||
|
<option value={SortType.TopYear}>
|
||||||
|
<T i18nKey="year">#</T>
|
||||||
|
</option>
|
||||||
|
<option value={SortType.TopAll}>
|
||||||
|
<T i18nKey="all">#</T>
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSortChange(i: SortSelect, event: any) {
|
||||||
|
i.state.sort = Number(event.target.value);
|
||||||
|
i.setState(i.state);
|
||||||
|
i.props.onChange(i.state.sort);
|
||||||
|
}
|
||||||
|
}
|
119
ui/src/components/user.tsx
vendored
119
ui/src/components/user.tsx
vendored
|
@ -9,6 +9,7 @@ import {
|
||||||
CommunityUser,
|
CommunityUser,
|
||||||
GetUserDetailsForm,
|
GetUserDetailsForm,
|
||||||
SortType,
|
SortType,
|
||||||
|
ListingType,
|
||||||
UserDetailsResponse,
|
UserDetailsResponse,
|
||||||
UserView,
|
UserView,
|
||||||
CommentResponse,
|
CommentResponse,
|
||||||
|
@ -28,6 +29,8 @@ import {
|
||||||
setTheme,
|
setTheme,
|
||||||
} from '../utils';
|
} from '../utils';
|
||||||
import { PostListing } from './post-listing';
|
import { PostListing } from './post-listing';
|
||||||
|
import { SortSelect } from './sort-select';
|
||||||
|
import { ListingTypeSelect } from './listing-type-select';
|
||||||
import { CommentNodes } from './comment-nodes';
|
import { CommentNodes } from './comment-nodes';
|
||||||
import { MomentTime } from './moment-time';
|
import { MomentTime } from './moment-time';
|
||||||
import { i18n } from '../i18next';
|
import { i18n } from '../i18next';
|
||||||
|
@ -89,6 +92,8 @@ export class User extends Component<any, UserState> {
|
||||||
userSettingsForm: {
|
userSettingsForm: {
|
||||||
show_nsfw: null,
|
show_nsfw: null,
|
||||||
theme: null,
|
theme: null,
|
||||||
|
default_sort_type: null,
|
||||||
|
default_listing_type: null,
|
||||||
auth: null,
|
auth: null,
|
||||||
},
|
},
|
||||||
userSettingsLoading: null,
|
userSettingsLoading: null,
|
||||||
|
@ -103,6 +108,13 @@ export class User extends Component<any, UserState> {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = this.emptyState;
|
this.state = this.emptyState;
|
||||||
|
this.handleSortChange = this.handleSortChange.bind(this);
|
||||||
|
this.handleUserSettingsSortTypeChange = this.handleUserSettingsSortTypeChange.bind(
|
||||||
|
this
|
||||||
|
);
|
||||||
|
this.handleUserSettingsListingTypeChange = this.handleUserSettingsListingTypeChange.bind(
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
this.state.user_id = Number(this.props.match.params.id);
|
this.state.user_id = Number(this.props.match.params.id);
|
||||||
this.state.username = this.props.match.params.username;
|
this.state.username = this.props.match.params.username;
|
||||||
|
@ -154,11 +166,14 @@ export class User extends Component<any, UserState> {
|
||||||
|
|
||||||
// Necessary for back button for some reason
|
// Necessary for back button for some reason
|
||||||
componentWillReceiveProps(nextProps: any) {
|
componentWillReceiveProps(nextProps: any) {
|
||||||
if (nextProps.history.action == 'POP') {
|
if (
|
||||||
this.state = this.emptyState;
|
nextProps.history.action == 'POP' ||
|
||||||
|
nextProps.history.action == 'PUSH'
|
||||||
|
) {
|
||||||
this.state.view = this.getViewFromProps(nextProps);
|
this.state.view = this.getViewFromProps(nextProps);
|
||||||
this.state.sort = this.getSortTypeFromProps(nextProps);
|
this.state.sort = this.getSortTypeFromProps(nextProps);
|
||||||
this.state.page = this.getPageFromProps(nextProps);
|
this.state.page = this.getPageFromProps(nextProps);
|
||||||
|
this.setState(this.state);
|
||||||
this.refetch();
|
this.refetch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,33 +234,13 @@ export class User extends Component<any, UserState> {
|
||||||
<T i18nKey="saved">#</T>
|
<T i18nKey="saved">#</T>
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<select
|
<span class="ml-2">
|
||||||
value={this.state.sort}
|
<SortSelect
|
||||||
onChange={linkEvent(this, this.handleSortChange)}
|
sort={this.state.sort}
|
||||||
class="custom-select custom-select-sm w-auto ml-2"
|
onChange={this.handleSortChange}
|
||||||
>
|
hideHot
|
||||||
<option disabled>
|
/>
|
||||||
<T i18nKey="sort_type">#</T>
|
</span>
|
||||||
</option>
|
|
||||||
<option value={SortType.New}>
|
|
||||||
<T i18nKey="new">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopDay}>
|
|
||||||
<T i18nKey="top_day">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopWeek}>
|
|
||||||
<T i18nKey="week">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopMonth}>
|
|
||||||
<T i18nKey="month">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopYear}>
|
|
||||||
<T i18nKey="year">#</T>
|
|
||||||
</option>
|
|
||||||
<option value={SortType.TopAll}>
|
|
||||||
<T i18nKey="all">#</T>
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -418,6 +413,32 @@ export class User extends Component<any, UserState> {
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<form className="form-group">
|
||||||
|
<div class="col-12">
|
||||||
|
<label>
|
||||||
|
<T i18nKey="sort_type" class="mr-2">
|
||||||
|
#
|
||||||
|
</T>
|
||||||
|
</label>
|
||||||
|
<ListingTypeSelect
|
||||||
|
type_={this.state.userSettingsForm.default_listing_type}
|
||||||
|
onChange={this.handleUserSettingsListingTypeChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form className="form-group">
|
||||||
|
<div class="col-12">
|
||||||
|
<label>
|
||||||
|
<T i18nKey="type" class="mr-2">
|
||||||
|
#
|
||||||
|
</T>
|
||||||
|
</label>
|
||||||
|
<SortSelect
|
||||||
|
sort={this.state.userSettingsForm.default_sort_type}
|
||||||
|
onChange={this.handleUserSettingsSortTypeChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
|
@ -436,9 +457,12 @@ export class User extends Component<any, UserState> {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group row mb-0">
|
<div class="form-group">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<button type="submit" class="btn btn-secondary mr-4">
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="btn btn-block btn-secondary mr-4"
|
||||||
|
>
|
||||||
{this.state.userSettingsLoading ? (
|
{this.state.userSettingsLoading ? (
|
||||||
<svg class="icon icon-spinner spin">
|
<svg class="icon icon-spinner spin">
|
||||||
<use xlinkHref="#icon-spinner"></use>
|
<use xlinkHref="#icon-spinner"></use>
|
||||||
|
@ -447,8 +471,13 @@ export class User extends Component<any, UserState> {
|
||||||
capitalizeFirstLetter(i18n.t('save'))
|
capitalizeFirstLetter(i18n.t('save'))
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div class="form-group mb-0">
|
||||||
|
<div class="col-12">
|
||||||
<button
|
<button
|
||||||
class="btn btn-danger"
|
class="btn btn-block btn-danger"
|
||||||
onClick={linkEvent(
|
onClick={linkEvent(
|
||||||
this,
|
this,
|
||||||
this.handleDeleteAccountShowConfirmToggle
|
this.handleDeleteAccountShowConfirmToggle
|
||||||
|
@ -608,12 +637,12 @@ export class User extends Component<any, UserState> {
|
||||||
WebSocketService.Instance.getUserDetails(form);
|
WebSocketService.Instance.getUserDetails(form);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSortChange(i: User, event: any) {
|
handleSortChange(val: SortType) {
|
||||||
i.state.sort = Number(event.target.value);
|
this.state.sort = val;
|
||||||
i.state.page = 1;
|
this.state.page = 1;
|
||||||
i.setState(i.state);
|
this.setState(this.state);
|
||||||
i.updateUrl();
|
this.updateUrl();
|
||||||
i.refetch();
|
this.refetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
handleViewChange(i: User, event: any) {
|
handleViewChange(i: User, event: any) {
|
||||||
|
@ -635,6 +664,16 @@ export class User extends Component<any, UserState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleUserSettingsSortTypeChange(val: SortType) {
|
||||||
|
this.state.userSettingsForm.default_sort_type = val;
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleUserSettingsListingTypeChange(val: ListingType) {
|
||||||
|
this.state.userSettingsForm.default_listing_type = val;
|
||||||
|
this.setState(this.state);
|
||||||
|
}
|
||||||
|
|
||||||
handleUserSettingsSubmit(i: User, event: any) {
|
handleUserSettingsSubmit(i: User, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
i.state.userSettingsLoading = true;
|
i.state.userSettingsLoading = true;
|
||||||
|
@ -685,6 +724,10 @@ export class User extends Component<any, UserState> {
|
||||||
this.state.userSettingsForm.theme = UserService.Instance.user.theme
|
this.state.userSettingsForm.theme = UserService.Instance.user.theme
|
||||||
? UserService.Instance.user.theme
|
? UserService.Instance.user.theme
|
||||||
: 'darkly';
|
: 'darkly';
|
||||||
|
this.state.userSettingsForm.default_sort_type =
|
||||||
|
UserService.Instance.user.default_sort_type;
|
||||||
|
this.state.userSettingsForm.default_listing_type =
|
||||||
|
UserService.Instance.user.default_listing_type;
|
||||||
}
|
}
|
||||||
document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
|
document.title = `/u/${this.state.user.name} - ${WebSocketService.Instance.site.name}`;
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
|
|
4
ui/src/interfaces.ts
vendored
4
ui/src/interfaces.ts
vendored
|
@ -75,6 +75,8 @@ export interface User {
|
||||||
username: string;
|
username: string;
|
||||||
show_nsfw: boolean;
|
show_nsfw: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
|
default_sort_type: SortType;
|
||||||
|
default_listing_type: ListingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserView {
|
export interface UserView {
|
||||||
|
@ -463,6 +465,8 @@ export interface LoginResponse {
|
||||||
export interface UserSettingsForm {
|
export interface UserSettingsForm {
|
||||||
show_nsfw: boolean;
|
show_nsfw: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
|
default_sort_type: SortType;
|
||||||
|
default_listing_type: ListingType;
|
||||||
auth: string;
|
auth: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
ui/src/services/WebSocketService.ts
vendored
4
ui/src/services/WebSocketService.ts
vendored
|
@ -53,8 +53,8 @@ export class WebSocketService {
|
||||||
.pipe(
|
.pipe(
|
||||||
retryWhen(errors =>
|
retryWhen(errors =>
|
||||||
errors.pipe(
|
errors.pipe(
|
||||||
delay(60000),
|
delay(1000)
|
||||||
take(999)
|
// take(999)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
2
ui/src/utils.ts
vendored
2
ui/src/utils.ts
vendored
|
@ -166,6 +166,8 @@ export function routeSortTypeToEnum(sort: string): SortType {
|
||||||
return SortType.TopWeek;
|
return SortType.TopWeek;
|
||||||
} else if (sort == 'topmonth') {
|
} else if (sort == 'topmonth') {
|
||||||
return SortType.TopMonth;
|
return SortType.TopMonth;
|
||||||
|
} else if (sort == 'topyear') {
|
||||||
|
return SortType.TopYear;
|
||||||
} else if (sort == 'topall') {
|
} else if (sort == 'topall') {
|
||||||
return SortType.TopAll;
|
return SortType.TopAll;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue