From 08b953c0aa0d9accea19fad0a18c3dd0c4bd174d Mon Sep 17 00:00:00 2001 From: Justin Hernandez Date: Wed, 1 Jul 2020 19:03:26 -0500 Subject: [PATCH 01/47] Remove karma count from search results --- ui/src/components/search.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ui/src/components/search.tsx b/ui/src/components/search.tsx index a02f035f..0e6bdfd3 100644 --- a/ui/src/components/search.tsx +++ b/ui/src/components/search.tsx @@ -263,9 +263,6 @@ export class Search extends Component { }} /> - {` - ${ - (i.data as UserView).comment_score - } comment karma`} )} @@ -339,7 +336,6 @@ export class Search extends Component { to={`/u/${user.name}`} >{`/u/${user.name}`} - {` - ${user.comment_score} comment karma`} ))} From 68e9755e593bbd8230eab2a123e822022721f071 Mon Sep 17 00:00:00 2001 From: Filip785 Date: Wed, 8 Jul 2020 02:28:47 +0200 Subject: [PATCH 02/47] Add cake day display in user page & posts/comments #682 --- .../2020-06-30-135809_remove_mat_views/up.sql | 2 + server/src/db/comment_view.rs | 7 ++++ server/src/db/post_view.rs | 5 +++ ui/src/components/cake-day.tsx | 41 +++++++++++++++++++ ui/src/components/comment-node.tsx | 8 ++++ ui/src/components/post-listing.tsx | 9 ++++ ui/src/components/symbols.tsx | 3 ++ ui/src/components/user.tsx | 10 +++++ ui/src/interfaces.ts | 2 + ui/translations/en.json | 4 +- 10 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 ui/src/components/cake-day.tsx diff --git a/server/migrations/2020-06-30-135809_remove_mat_views/up.sql b/server/migrations/2020-06-30-135809_remove_mat_views/up.sql index bd792a8b..9e2fa59c 100644 --- a/server/migrations/2020-06-30-135809_remove_mat_views/up.sql +++ b/server/migrations/2020-06-30-135809_remove_mat_views/up.sql @@ -106,6 +106,7 @@ select u.actor_id as creator_actor_id, u."local" as creator_local, u."name" as creator_name, + u.published as creator_published, u.avatar as creator_avatar, u.banned as banned, cb.id::bool as banned_from_community, @@ -490,6 +491,7 @@ select u.actor_id as creator_actor_id, u.local as creator_local, u.name as creator_name, + u.published as creator_published, u.avatar as creator_avatar, -- score details coalesce(cl.total, 0) as score, diff --git a/server/src/db/comment_view.rs b/server/src/db/comment_view.rs index d1b27a3c..75ed4cb7 100644 --- a/server/src/db/comment_view.rs +++ b/server/src/db/comment_view.rs @@ -28,6 +28,7 @@ table! { creator_local -> Bool, creator_name -> Varchar, creator_avatar -> Nullable, + creator_published -> Timestamp, score -> BigInt, upvotes -> BigInt, downvotes -> BigInt, @@ -63,6 +64,7 @@ table! { creator_local -> Bool, creator_name -> Varchar, creator_avatar -> Nullable, + creator_published -> Timestamp, score -> BigInt, upvotes -> BigInt, downvotes -> BigInt, @@ -101,6 +103,7 @@ pub struct CommentView { pub creator_local: bool, pub creator_name: String, pub creator_avatar: Option, + pub creator_published: chrono::NaiveDateTime, pub score: i64, pub upvotes: i64, pub downvotes: i64, @@ -314,6 +317,7 @@ table! { creator_local -> Bool, creator_name -> Varchar, creator_avatar -> Nullable, + creator_published -> Timestamp, score -> BigInt, upvotes -> BigInt, downvotes -> BigInt, @@ -353,6 +357,7 @@ pub struct ReplyView { pub creator_local: bool, pub creator_name: String, pub creator_avatar: Option, + pub creator_published: chrono::NaiveDateTime, pub score: i64, pub upvotes: i64, pub downvotes: i64, @@ -576,6 +581,7 @@ mod tests { published: inserted_comment.published, updated: None, creator_name: inserted_user.name.to_owned(), + creator_published: inserted_user.published, creator_avatar: None, score: 1, downvotes: 0, @@ -609,6 +615,7 @@ mod tests { published: inserted_comment.published, updated: None, creator_name: inserted_user.name.to_owned(), + creator_published: inserted_user.published, creator_avatar: None, score: 1, downvotes: 0, diff --git a/server/src/db/post_view.rs b/server/src/db/post_view.rs index 808cf28c..cda5cecf 100644 --- a/server/src/db/post_view.rs +++ b/server/src/db/post_view.rs @@ -28,6 +28,7 @@ table! { creator_actor_id -> Text, creator_local -> Bool, creator_name -> Varchar, + creator_published -> Timestamp, creator_avatar -> Nullable, banned -> Bool, banned_from_community -> Bool, @@ -75,6 +76,7 @@ table! { creator_actor_id -> Text, creator_local -> Bool, creator_name -> Varchar, + creator_published -> Timestamp, creator_avatar -> Nullable, banned -> Bool, banned_from_community -> Bool, @@ -125,6 +127,7 @@ pub struct PostView { pub creator_actor_id: String, pub creator_local: bool, pub creator_name: String, + pub creator_published: chrono::NaiveDateTime, pub creator_avatar: Option, pub banned: bool, pub banned_from_community: bool, @@ -499,6 +502,7 @@ mod tests { body: None, creator_id: inserted_user.id, creator_name: user_name.to_owned(), + creator_published: inserted_user.published, creator_avatar: None, banned: false, banned_from_community: false, @@ -548,6 +552,7 @@ mod tests { stickied: false, creator_id: inserted_user.id, creator_name: user_name, + creator_published: inserted_user.published, creator_avatar: None, banned: false, banned_from_community: false, diff --git a/ui/src/components/cake-day.tsx b/ui/src/components/cake-day.tsx new file mode 100644 index 00000000..67ac7f8b --- /dev/null +++ b/ui/src/components/cake-day.tsx @@ -0,0 +1,41 @@ +import { Component } from 'inferno'; +import moment from 'moment'; +import { i18n } from '../i18next'; + +interface CakeDayProps { + creator_name: string; + creator_published: string; +} + +export class CakeDay extends Component { + render() { + const { creator_name, creator_published } = this.props; + + return ( + this.isCakeDay(creator_published) && ( +
+ + + +
+ ) + ); + } + + isCakeDay(input: string): boolean { + const userCreationDate = moment.utc(input).local(); + const currentDate = moment(new Date()); + + return ( + userCreationDate.date() === currentDate.date() && + userCreationDate.month() === currentDate.month() + ); + } + + cakeDayTippy(creator_name: string): string { + return i18n.t('cake_day_info', { creator_name }); + } +} diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index 155efe8e..762344aa 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -33,6 +33,7 @@ import { CommentForm } from './comment-form'; import { CommentNodes } from './comment-nodes'; import { UserListing } from './user-listing'; import { i18n } from '../i18next'; +import { CakeDay } from './cake-day'; interface CommentNodeState { showReply: boolean; @@ -124,6 +125,7 @@ export class CommentNode extends Component { render() { let node = this.props.node; + const { creator_name, creator_published } = node.comment; return (
{ }} /> + + + {this.isMod && (
{i18n.t('mod')} diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 3d608842..e6b9721c 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -35,6 +35,7 @@ import { previewLines, } from '../utils'; import { i18n } from '../i18next'; +import { CakeDay } from './cake-day'; interface PostListingState { showEdit: boolean; @@ -253,6 +254,8 @@ export class PostListing extends Component { listing() { let post = this.props.post; + const { creator_name, creator_published } = post; + return (
@@ -432,6 +435,12 @@ export class PostListing extends Component { actor_id: post.creator_actor_id, }} /> + + + {this.isMod && ( {i18n.t('mod')} diff --git a/ui/src/components/symbols.tsx b/ui/src/components/symbols.tsx index 77d7a086..3386dbe5 100644 --- a/ui/src/components/symbols.tsx +++ b/ui/src/components/symbols.tsx @@ -168,6 +168,9 @@ export class Symbols extends Component { + + + ); diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index 69914fd3..4f680324 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.tsx @@ -46,6 +46,7 @@ import { ListingTypeSelect } from './listing-type-select'; import { CommentNodes } from './comment-nodes'; import { MomentTime } from './moment-time'; import { i18n } from '../i18next'; +import moment from 'moment'; enum View { Overview, @@ -412,6 +413,15 @@ export class User extends Component { )} +
+ + + + + {i18n.t('cake_day_title')}{' '} + {moment.utc(user.published).local().format('MMM DD, YYYY')} + +
{i18n.t('joined')}
diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index 7e29319f..774836a2 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -183,6 +183,7 @@ export interface Post { creator_actor_id: string; creator_local: boolean; creator_name: string; + creator_published: string; creator_avatar?: string; community_actor_id: string; community_local: boolean; @@ -227,6 +228,7 @@ export interface Comment { creator_local: boolean; creator_name: string; creator_avatar?: string; + creator_published: string; score: number; upvotes: number; downvotes: number; diff --git a/ui/translations/en.json b/ui/translations/en.json index 62b11ce4..3dda5948 100644 --- a/ui/translations/en.json +++ b/ui/translations/en.json @@ -265,5 +265,7 @@ "action": "Action", "emoji_picker": "Emoji Picker", "block_leaving": "Are you sure you want to leave?", - "what_is": "What is" + "what_is": "What is", + "cake_day_title": "Cake day:", + "cake_day_info": "It's {{ creator_name }}'s cake day today!" } From 8fe8836bc263be11895fafa958409499c9e9fc9d Mon Sep 17 00:00:00 2001 From: Filip785 Date: Wed, 8 Jul 2020 19:46:18 +0200 Subject: [PATCH 03/47] Updates to PR as requested --- ui/src/components/cake-day.tsx | 35 ++++++++++-------------------- ui/src/components/comment-node.tsx | 9 ++++---- ui/src/components/post-listing.tsx | 10 ++++----- ui/src/utils.ts | 11 ++++++++++ 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/ui/src/components/cake-day.tsx b/ui/src/components/cake-day.tsx index 67ac7f8b..be807184 100644 --- a/ui/src/components/cake-day.tsx +++ b/ui/src/components/cake-day.tsx @@ -1,37 +1,26 @@ import { Component } from 'inferno'; -import moment from 'moment'; import { i18n } from '../i18next'; interface CakeDayProps { creator_name: string; - creator_published: string; + is_post_creator?: boolean; } export class CakeDay extends Component { render() { - const { creator_name, creator_published } = this.props; + const { creator_name, is_post_creator } = this.props; return ( - this.isCakeDay(creator_published) && ( -
- - - -
- ) - ); - } - - isCakeDay(input: string): boolean { - const userCreationDate = moment.utc(input).local(); - const currentDate = moment(new Date()); - - return ( - userCreationDate.date() === currentDate.date() && - userCreationDate.month() === currentDate.month() +
+ + + +
); } diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index ab9321bd..2d1426b0 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -26,6 +26,7 @@ import { isMod, setupTippy, colorList, + isCakeDay, } from '../utils'; import moment from 'moment'; import { MomentTime } from './moment-time'; @@ -126,7 +127,6 @@ export class CommentNode extends Component { render() { let node = this.props.node; - const { creator_name, creator_published } = node.comment; return (
{ /> - + {isCakeDay(node.comment.creator_published) && ( + + )} {this.isMod && (
diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 7199510b..92a2f9cb 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -33,6 +33,7 @@ import { setupTippy, hostname, previewLines, + isCakeDay, } from '../utils'; import { i18n } from '../i18next'; import { CakeDay } from './cake-day'; @@ -258,8 +259,6 @@ export class PostListing extends Component { listing() { let post = this.props.post; - const { creator_name, creator_published } = post; - return (
@@ -440,10 +439,9 @@ export class PostListing extends Component { }} /> - + {isCakeDay(post.creator_published) && ( + + )} {this.isMod && ( diff --git a/ui/src/utils.ts b/ui/src/utils.ts index f65ca4e3..3ccaae12 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -53,6 +53,7 @@ import emojiShortName from 'emoji-short-name'; import Toastify from 'toastify-js'; import tippy from 'tippy.js'; import EmojiButton from '@joeattardi/emoji-button'; +import moment from 'moment'; export const repoUrl = 'https://github.com/LemmyNet/lemmy'; export const helpGuideUrl = '/docs/about_guide.html'; @@ -489,6 +490,16 @@ export function showAvatars(): boolean { ); } +export function isCakeDay(creator_published: string): boolean { + const userCreationDate = moment.utc(creator_published).local(); + const currentDate = moment(new Date()); + + return ( + userCreationDate.date() === currentDate.date() && + userCreationDate.month() === currentDate.month() + ); +} + // Converts to image thumbnail export function pictrsImage(hash: string, thumbnail: boolean = false): string { let root = `/pictrs/image`; From 75251f6e7868a12420be06d08168dbdf1ed4bc88 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Jul 2020 09:47:26 -0400 Subject: [PATCH 04/47] Adding select quoting of text for comments. Fixes #790 --- ui/src/components/comment-form.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 770c127c..32bc3786 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -98,7 +98,7 @@ export class CommentForm extends Component { } componentDidMount() { - var textarea: any = document.getElementById(this.id); + let textarea: any = document.getElementById(this.id); autosize(textarea); this.tribute.attach(textarea); textarea.addEventListener('tribute-replaced', () => { @@ -106,6 +106,22 @@ export class CommentForm extends Component { this.setState(this.state); autosize.update(textarea); }); + + // Quoting of selected text + let selectedText = window.getSelection().toString(); + if (selectedText) { + let quotedText = + selectedText + .split('\n') + .map(t => `> ${t}`) + .join('\n') + '\n\n'; + this.state.commentForm.content = quotedText; + this.setState(this.state); + // Not sure why this needs a delay + setTimeout(() => autosize.update(textarea), 10); + } + + textarea.focus(); } componentDidUpdate() { From 558644b8b364697159c5832908b8497a44d6179d Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Jul 2020 10:15:12 -0400 Subject: [PATCH 05/47] Adding lemmy's devs / contributors to the sidebar. Fixes #743 --- ui/assets/css/main.css | 7 +++++++ ui/src/components/main.tsx | 10 +++++++--- ui/translations/en.json | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ui/assets/css/main.css b/ui/assets/css/main.css index fd65148c..9f744fb1 100644 --- a/ui/assets/css/main.css +++ b/ui/assets/css/main.css @@ -264,3 +264,10 @@ pre { width: 0px !important; padding: 0 !important; } + +br.big { + display: block; + content: ""; + margin-top: 1rem; +} + diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 20735049..9e9027d6 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -373,17 +373,21 @@ export class Main extends Component { # # -

+

#

# -

+

# -

+

# # # # +

+ + # +

diff --git a/ui/translations/en.json b/ui/translations/en.json index 62b11ce4..98b31114 100644 --- a/ui/translations/en.json +++ b/ui/translations/en.json @@ -217,7 +217,7 @@ "no": "no", "powered_by": "Powered by", "landing_0": - "Lemmy is a <1>link aggregator / reddit alternative, intended to work in the <2>fediverse.<3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB). Federation into the ActivityPub network is on the roadmap. <5>This is a <6>very early beta version, and a lot of features are currently broken or missing. <7>Suggest new features or report bugs <8>here.<9>Made with <10>Rust, <11>Actix, <12>Inferno, <13>Typescript.", + "Lemmy is a <1>link aggregator / reddit alternative, intended to work in the <2>fediverse.<3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB). Federation into the ActivityPub network is on the roadmap. <5>This is a <6>very early beta version, and a lot of features are currently broken or missing. <7>Suggest new features or report bugs <8>here.<9>Made with <10>Rust, <11>Actix, <12>Inferno, <13>Typescript. <14> <15>Thank you to our contributors: dessalines, Nutomic, asonix, zacanger, and iav.", "not_logged_in": "Not logged in.", "logged_in": "Logged in.", "site_saved": "Site Saved.", From 20f9bde88f52ce875be4d0dc4bd5dd346dfe6b84 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Jul 2020 10:44:05 -0400 Subject: [PATCH 06/47] Making comment collapse and lightning buttons not spans. Fixes #884 --- ui/src/components/comment-node.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index 839a01dc..49b56629 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -189,8 +189,8 @@ export class CommentNode extends Component { )} -
{this.state.collapsed ? ( @@ -202,9 +202,11 @@ export class CommentNode extends Component { )} -
- + {/* This is an expanding spacer for mobile */} +
+ From 7c35fc546bb148047087db6ed95b1579bab08238 Mon Sep 17 00:00:00 2001 From: Filip785 Date: Thu, 9 Jul 2020 17:19:30 +0200 Subject: [PATCH 07/47] Create new migration to add `creator_published` field to the `post_view` and `comment_view` --- .../2020-06-30-135809_remove_mat_views/up.sql | 2 - .../down.sql | 388 +++++++++++++++++ .../up.sql | 390 ++++++++++++++++++ server/src/schema.rs | 2 + ui/src/utils.ts | 4 +- 5 files changed, 783 insertions(+), 3 deletions(-) create mode 100644 server/migrations/2020-07-08-202609_add_creator_published/down.sql create mode 100644 server/migrations/2020-07-08-202609_add_creator_published/up.sql diff --git a/server/migrations/2020-06-30-135809_remove_mat_views/up.sql b/server/migrations/2020-06-30-135809_remove_mat_views/up.sql index 9e2fa59c..bd792a8b 100644 --- a/server/migrations/2020-06-30-135809_remove_mat_views/up.sql +++ b/server/migrations/2020-06-30-135809_remove_mat_views/up.sql @@ -106,7 +106,6 @@ select u.actor_id as creator_actor_id, u."local" as creator_local, u."name" as creator_name, - u.published as creator_published, u.avatar as creator_avatar, u.banned as banned, cb.id::bool as banned_from_community, @@ -491,7 +490,6 @@ select u.actor_id as creator_actor_id, u.local as creator_local, u.name as creator_name, - u.published as creator_published, u.avatar as creator_avatar, -- score details coalesce(cl.total, 0) as score, diff --git a/server/migrations/2020-07-08-202609_add_creator_published/down.sql b/server/migrations/2020-07-08-202609_add_creator_published/down.sql new file mode 100644 index 00000000..b8e4452e --- /dev/null +++ b/server/migrations/2020-07-08-202609_add_creator_published/down.sql @@ -0,0 +1,388 @@ +drop view user_mention_view; +drop view reply_fast_view; +drop view comment_fast_view; +drop view comment_view; + +drop view user_mention_fast_view; +drop table comment_aggregates_fast; +drop view comment_aggregates_view; + +create view comment_aggregates_view as +select + ct.*, + -- community details + p.community_id, + c.actor_id as community_actor_id, + c."local" as community_local, + c."name" as community_name, + -- creator details + u.banned as banned, + coalesce(cb.id, 0)::bool as banned_from_community, + u.actor_id as creator_actor_id, + u.local as creator_local, + u.name as creator_name, + u.avatar as creator_avatar, + -- score details + coalesce(cl.total, 0) as score, + coalesce(cl.up, 0) as upvotes, + coalesce(cl.down, 0) as downvotes, + hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank +from comment ct +left join post p on ct.post_id = p.id +left join community c on p.community_id = c.id +left join user_ u on ct.creator_id = u.id +left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id +left join ( + select + l.comment_id as id, + sum(l.score) as total, + count(case when l.score = 1 then 1 else null end) as up, + count(case when l.score = -1 then 1 else null end) as down + from comment_like l + group by comment_id +) as cl on cl.id = ct.id; + +create or replace view comment_view as ( +select + cav.*, + us.user_id as user_id, + us.my_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_saved::bool as saved +from comment_aggregates_view cav +cross join lateral ( + select + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + coalesce(cf.id, 0) as is_subbed, + coalesce(cs.id, 0) as is_saved + from user_ u + left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id + left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id + left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id +) as us + +union all + +select + cav.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from comment_aggregates_view cav +); + +create table comment_aggregates_fast as select * from comment_aggregates_view; +alter table comment_aggregates_fast add primary key (id); + +create view comment_fast_view as +select + cav.*, + us.user_id as user_id, + us.my_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_saved::bool as saved +from comment_aggregates_fast cav +cross join lateral ( + select + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + coalesce(cf.id, 0) as is_subbed, + coalesce(cs.id, 0) as is_saved + from user_ u + left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id + left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id + left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id +) as us + +union all + +select + cav.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from comment_aggregates_fast cav; + +create view user_mention_view as +select + c.id, + um.id as user_mention_id, + c.creator_id, + c.creator_actor_id, + c.creator_local, + c.post_id, + c.parent_id, + c.content, + c.removed, + um.read, + c.published, + c.updated, + c.deleted, + c.community_id, + c.community_actor_id, + c.community_local, + c.community_name, + c.banned, + c.banned_from_community, + c.creator_name, + c.creator_avatar, + c.score, + c.upvotes, + c.downvotes, + c.hot_rank, + c.user_id, + c.my_vote, + c.saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from user_mention um, comment_view c +where um.comment_id = c.id; + +create view user_mention_fast_view as +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.creator_actor_id, + ac.creator_local, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_actor_id, + ac.community_local, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from user_ u +cross join ( + select + ca.* + from comment_aggregates_fast ca +) ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id +left join user_mention um on um.comment_id = ac.id + +union all + +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.creator_actor_id, + ac.creator_local, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_actor_id, + ac.community_local, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + null as user_id, + null as my_vote, + null as saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from comment_aggregates_fast ac +left join user_mention um on um.comment_id = ac.id +; + +-- Do the reply_view referencing the comment_fast_view +create view reply_fast_view as +with closereply as ( + select + c2.id, + c2.creator_id as sender_id, + c.creator_id as recipient_id + from comment c + inner join comment c2 on c.id = c2.parent_id + where c2.creator_id != c.creator_id + -- Do union where post is null + union + select + c.id, + c.creator_id as sender_id, + p.creator_id as recipient_id + from comment c, post p + where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +) +select cv.*, +closereply.recipient_id +from comment_fast_view cv, closereply +where closereply.id = cv.id +; + +-- add creator_published to the post view +drop view post_fast_view; +drop table post_aggregates_fast; +drop view post_view; +drop view post_aggregates_view; + +create view post_aggregates_view as +select + p.*, + -- creator details + u.actor_id as creator_actor_id, + u."local" as creator_local, + u."name" as creator_name, + u.avatar as creator_avatar, + u.banned as banned, + cb.id::bool as banned_from_community, + -- community details + c.actor_id as community_actor_id, + c."local" as community_local, + c."name" as community_name, + c.removed as community_removed, + c.deleted as community_deleted, + c.nsfw as community_nsfw, + -- post score data/comment count + coalesce(ct.comments, 0) as number_of_comments, + coalesce(pl.score, 0) as score, + coalesce(pl.upvotes, 0) as upvotes, + coalesce(pl.downvotes, 0) as downvotes, + hot_rank( + coalesce(pl.score , 0), ( + case + when (p.published < ('now'::timestamp - '1 month'::interval)) + then p.published + else greatest(ct.recent_comment_time, p.published) + end + ) + ) as hot_rank, + ( + case + when (p.published < ('now'::timestamp - '1 month'::interval)) + then p.published + else greatest(ct.recent_comment_time, p.published) + end + ) as newest_activity_time +from post p +left join user_ u on p.creator_id = u.id +left join community_user_ban cb on p.creator_id = cb.user_id and p.community_id = cb.community_id +left join community c on p.community_id = c.id +left join ( + select + post_id, + count(*) as comments, + max(published) as recent_comment_time + from comment + group by post_id +) ct on ct.post_id = p.id +left join ( + select + post_id, + sum(score) as score, + sum(score) filter (where score = 1) as upvotes, + -sum(score) filter (where score = -1) as downvotes + from post_like + group by post_id +) pl on pl.post_id = p.id +order by p.id; + +create view post_view as +select + pav.*, + us.id as user_id, + us.user_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_read::bool as read, + us.is_saved::bool as saved +from post_aggregates_view pav +cross join lateral ( + select + u.id, + coalesce(cf.community_id, 0) as is_subbed, + coalesce(pr.post_id, 0) as is_read, + coalesce(ps.post_id, 0) as is_saved, + coalesce(pl.score, 0) as user_vote + from user_ u + left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id + left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id + left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id + left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id + left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id +) as us + +union all + +select +pav.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from post_aggregates_view pav; + +create table post_aggregates_fast as select * from post_aggregates_view; +alter table post_aggregates_fast add primary key (id); + +create view post_fast_view as +select + pav.*, + us.id as user_id, + us.user_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_read::bool as read, + us.is_saved::bool as saved +from post_aggregates_fast pav +cross join lateral ( + select + u.id, + coalesce(cf.community_id, 0) as is_subbed, + coalesce(pr.post_id, 0) as is_read, + coalesce(ps.post_id, 0) as is_saved, + coalesce(pl.score, 0) as user_vote + from user_ u + left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id + left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id + left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id + left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id + left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id +) as us + +union all + +select +pav.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from post_aggregates_fast pav; \ No newline at end of file diff --git a/server/migrations/2020-07-08-202609_add_creator_published/up.sql b/server/migrations/2020-07-08-202609_add_creator_published/up.sql new file mode 100644 index 00000000..1f2b59ea --- /dev/null +++ b/server/migrations/2020-07-08-202609_add_creator_published/up.sql @@ -0,0 +1,390 @@ +drop view user_mention_view; +drop view reply_fast_view; +drop view comment_fast_view; +drop view comment_view; + +drop view user_mention_fast_view; +drop table comment_aggregates_fast; +drop view comment_aggregates_view; + +create view comment_aggregates_view as +select + ct.*, + -- community details + p.community_id, + c.actor_id as community_actor_id, + c."local" as community_local, + c."name" as community_name, + -- creator details + u.banned as banned, + coalesce(cb.id, 0)::bool as banned_from_community, + u.actor_id as creator_actor_id, + u.local as creator_local, + u.name as creator_name, + u.published as creator_published, + u.avatar as creator_avatar, + -- score details + coalesce(cl.total, 0) as score, + coalesce(cl.up, 0) as upvotes, + coalesce(cl.down, 0) as downvotes, + hot_rank(coalesce(cl.total, 0), ct.published) as hot_rank +from comment ct +left join post p on ct.post_id = p.id +left join community c on p.community_id = c.id +left join user_ u on ct.creator_id = u.id +left join community_user_ban cb on ct.creator_id = cb.user_id and p.id = ct.post_id and p.community_id = cb.community_id +left join ( + select + l.comment_id as id, + sum(l.score) as total, + count(case when l.score = 1 then 1 else null end) as up, + count(case when l.score = -1 then 1 else null end) as down + from comment_like l + group by comment_id +) as cl on cl.id = ct.id; + +create or replace view comment_view as ( +select + cav.*, + us.user_id as user_id, + us.my_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_saved::bool as saved +from comment_aggregates_view cav +cross join lateral ( + select + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + coalesce(cf.id, 0) as is_subbed, + coalesce(cs.id, 0) as is_saved + from user_ u + left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id + left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id + left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id +) as us + +union all + +select + cav.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from comment_aggregates_view cav +); + +create table comment_aggregates_fast as select * from comment_aggregates_view; +alter table comment_aggregates_fast add primary key (id); + +create view comment_fast_view as +select + cav.*, + us.user_id as user_id, + us.my_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_saved::bool as saved +from comment_aggregates_fast cav +cross join lateral ( + select + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + coalesce(cf.id, 0) as is_subbed, + coalesce(cs.id, 0) as is_saved + from user_ u + left join comment_like cl on u.id = cl.user_id and cav.id = cl.comment_id + left join comment_saved cs on u.id = cs.user_id and cs.comment_id = cav.id + left join community_follower cf on u.id = cf.user_id and cav.community_id = cf.community_id +) as us + +union all + +select + cav.*, + null as user_id, + null as my_vote, + null as subscribed, + null as saved +from comment_aggregates_fast cav; + +create view user_mention_view as +select + c.id, + um.id as user_mention_id, + c.creator_id, + c.creator_actor_id, + c.creator_local, + c.post_id, + c.parent_id, + c.content, + c.removed, + um.read, + c.published, + c.updated, + c.deleted, + c.community_id, + c.community_actor_id, + c.community_local, + c.community_name, + c.banned, + c.banned_from_community, + c.creator_name, + c.creator_avatar, + c.score, + c.upvotes, + c.downvotes, + c.hot_rank, + c.user_id, + c.my_vote, + c.saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from user_mention um, comment_view c +where um.comment_id = c.id; + +create view user_mention_fast_view as +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.creator_actor_id, + ac.creator_local, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_actor_id, + ac.community_local, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + u.id as user_id, + coalesce(cl.score, 0) as my_vote, + (select cs.id::bool from comment_saved cs where u.id = cs.user_id and cs.comment_id = ac.id) as saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from user_ u +cross join ( + select + ca.* + from comment_aggregates_fast ca +) ac +left join comment_like cl on u.id = cl.user_id and ac.id = cl.comment_id +left join user_mention um on um.comment_id = ac.id + +union all + +select + ac.id, + um.id as user_mention_id, + ac.creator_id, + ac.creator_actor_id, + ac.creator_local, + ac.post_id, + ac.parent_id, + ac.content, + ac.removed, + um.read, + ac.published, + ac.updated, + ac.deleted, + ac.community_id, + ac.community_actor_id, + ac.community_local, + ac.community_name, + ac.banned, + ac.banned_from_community, + ac.creator_name, + ac.creator_avatar, + ac.score, + ac.upvotes, + ac.downvotes, + ac.hot_rank, + null as user_id, + null as my_vote, + null as saved, + um.recipient_id, + (select actor_id from user_ u where u.id = um.recipient_id) as recipient_actor_id, + (select local from user_ u where u.id = um.recipient_id) as recipient_local +from comment_aggregates_fast ac +left join user_mention um on um.comment_id = ac.id +; + +-- Do the reply_view referencing the comment_fast_view +create view reply_fast_view as +with closereply as ( + select + c2.id, + c2.creator_id as sender_id, + c.creator_id as recipient_id + from comment c + inner join comment c2 on c.id = c2.parent_id + where c2.creator_id != c.creator_id + -- Do union where post is null + union + select + c.id, + c.creator_id as sender_id, + p.creator_id as recipient_id + from comment c, post p + where c.post_id = p.id and c.parent_id is null and c.creator_id != p.creator_id +) +select cv.*, +closereply.recipient_id +from comment_fast_view cv, closereply +where closereply.id = cv.id +; + +-- add creator_published to the post view +drop view post_fast_view; +drop table post_aggregates_fast; +drop view post_view; +drop view post_aggregates_view; + +create view post_aggregates_view as +select + p.*, + -- creator details + u.actor_id as creator_actor_id, + u."local" as creator_local, + u."name" as creator_name, + u.published as creator_published, + u.avatar as creator_avatar, + u.banned as banned, + cb.id::bool as banned_from_community, + -- community details + c.actor_id as community_actor_id, + c."local" as community_local, + c."name" as community_name, + c.removed as community_removed, + c.deleted as community_deleted, + c.nsfw as community_nsfw, + -- post score data/comment count + coalesce(ct.comments, 0) as number_of_comments, + coalesce(pl.score, 0) as score, + coalesce(pl.upvotes, 0) as upvotes, + coalesce(pl.downvotes, 0) as downvotes, + hot_rank( + coalesce(pl.score , 0), ( + case + when (p.published < ('now'::timestamp - '1 month'::interval)) + then p.published + else greatest(ct.recent_comment_time, p.published) + end + ) + ) as hot_rank, + ( + case + when (p.published < ('now'::timestamp - '1 month'::interval)) + then p.published + else greatest(ct.recent_comment_time, p.published) + end + ) as newest_activity_time +from post p +left join user_ u on p.creator_id = u.id +left join community_user_ban cb on p.creator_id = cb.user_id and p.community_id = cb.community_id +left join community c on p.community_id = c.id +left join ( + select + post_id, + count(*) as comments, + max(published) as recent_comment_time + from comment + group by post_id +) ct on ct.post_id = p.id +left join ( + select + post_id, + sum(score) as score, + sum(score) filter (where score = 1) as upvotes, + -sum(score) filter (where score = -1) as downvotes + from post_like + group by post_id +) pl on pl.post_id = p.id +order by p.id; + +create view post_view as +select + pav.*, + us.id as user_id, + us.user_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_read::bool as read, + us.is_saved::bool as saved +from post_aggregates_view pav +cross join lateral ( + select + u.id, + coalesce(cf.community_id, 0) as is_subbed, + coalesce(pr.post_id, 0) as is_read, + coalesce(ps.post_id, 0) as is_saved, + coalesce(pl.score, 0) as user_vote + from user_ u + left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id + left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id + left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id + left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id + left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id +) as us + +union all + +select +pav.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from post_aggregates_view pav; + +create table post_aggregates_fast as select * from post_aggregates_view; +alter table post_aggregates_fast add primary key (id); + +create view post_fast_view as +select + pav.*, + us.id as user_id, + us.user_vote as my_vote, + us.is_subbed::bool as subscribed, + us.is_read::bool as read, + us.is_saved::bool as saved +from post_aggregates_fast pav +cross join lateral ( + select + u.id, + coalesce(cf.community_id, 0) as is_subbed, + coalesce(pr.post_id, 0) as is_read, + coalesce(ps.post_id, 0) as is_saved, + coalesce(pl.score, 0) as user_vote + from user_ u + left join community_user_ban cb on u.id = cb.user_id and cb.community_id = pav.community_id + left join community_follower cf on u.id = cf.user_id and cf.community_id = pav.community_id + left join post_read pr on u.id = pr.user_id and pr.post_id = pav.id + left join post_saved ps on u.id = ps.user_id and ps.post_id = pav.id + left join post_like pl on u.id = pl.user_id and pav.id = pl.post_id +) as us + +union all + +select +pav.*, +null as user_id, +null as my_vote, +null as subscribed, +null as read, +null as saved +from post_aggregates_fast pav; \ No newline at end of file diff --git a/server/src/schema.rs b/server/src/schema.rs index 0367c750..18a522df 100644 --- a/server/src/schema.rs +++ b/server/src/schema.rs @@ -56,6 +56,7 @@ table! { creator_actor_id -> Nullable, creator_local -> Nullable, creator_name -> Nullable, + creator_published -> Nullable, creator_avatar -> Nullable, score -> Nullable, upvotes -> Nullable, @@ -317,6 +318,7 @@ table! { creator_actor_id -> Nullable, creator_local -> Nullable, creator_name -> Nullable, + creator_published -> Nullable, creator_avatar -> Nullable, banned -> Nullable, banned_from_community -> Nullable, diff --git a/ui/src/utils.ts b/ui/src/utils.ts index a418c569..e38834aa 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -503,7 +503,9 @@ export function showAvatars(): boolean { } export function isCakeDay(creator_published: string): boolean { - const userCreationDate = moment.utc(creator_published).local(); + // moment(undefined) or moment.utc(undefined) returns the current date/time + // moment(null) or moment.utc(null) returns null + const userCreationDate = moment.utc(creator_published || null).local(); const currentDate = moment(new Date()); return ( From db09730d5f391c37bde87f59ed2ea6f3418034e4 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Jul 2020 13:32:23 -0400 Subject: [PATCH 08/47] Removing twemoji, and the massive emoji picker. Fixes #895 --- ui/package.json | 2 - ui/src/components/comment-form.tsx | 29 -------- ui/src/components/post-form.tsx | 29 -------- ui/src/utils.ts | 17 +---- ui/yarn.lock | 110 +---------------------------- 5 files changed, 3 insertions(+), 184 deletions(-) diff --git a/ui/package.json b/ui/package.json index 0101ce13..2819433a 100644 --- a/ui/package.json +++ b/ui/package.json @@ -15,7 +15,6 @@ }, "keywords": [], "dependencies": { - "@joeattardi/emoji-button": "^2.12.1", "@types/autosize": "^3.0.6", "@types/js-cookie": "^2.2.6", "@types/jwt-decode": "^2.2.1", @@ -47,7 +46,6 @@ "tippy.js": "^6.1.1", "toastify-js": "^1.7.0", "tributejs": "^5.1.3", - "twemoji": "^12.1.2", "ws": "^7.2.3" }, "devDependencies": { diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 32bc3786..22f871d2 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -17,7 +17,6 @@ import { toast, setupTribute, wsJsonToRes, - emojiPicker, pictrsDeleteToast, } from '../utils'; import { WebSocketService, UserService } from '../services'; @@ -72,7 +71,6 @@ export class CommentForm extends Component { super(props, context); this.tribute = setupTribute(); - this.setupEmojiPicker(); this.state = this.emptyState; @@ -241,15 +239,6 @@ export class CommentForm extends Component { )} - - - - -
@@ -257,20 +246,6 @@ export class CommentForm extends Component { ); } - setupEmojiPicker() { - emojiPicker.on('emoji', twemojiHtmlStr => { - if (this.state.commentForm.content == null) { - this.state.commentForm.content = ''; - } - var el = document.createElement('div'); - el.innerHTML = twemojiHtmlStr; - let nativeUnicode = (el.childNodes[0] as HTMLElement).getAttribute('alt'); - let shortName = `:${emojiShortName[nativeUnicode]}:`; - this.state.commentForm.content += shortName; - this.setState(this.state); - }); - } - handleFinished(op: UserOperation, data: CommentResponse) { let isReply = this.props.node !== undefined && data.comment.parent_id !== null; @@ -318,10 +293,6 @@ export class CommentForm extends Component { i.setState(i.state); } - handleEmojiPickerClick(_i: CommentForm, event: any) { - emojiPicker.togglePicker(event.target); - } - handleCommentContentChange(i: CommentForm, event: any) { i.state.commentForm.content = event.target.value; i.setState(i.state); diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index a88d38c7..fc7884d7 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -33,7 +33,6 @@ import { randomStr, setupTribute, setupTippy, - emojiPicker, hostname, pictrsDeleteToast, } from '../utils'; @@ -95,7 +94,6 @@ export class PostForm extends Component { this.fetchPageTitle = debounce(this.fetchPageTitle).bind(this); this.tribute = setupTribute(); - this.setupEmojiPicker(); this.state = this.emptyState; @@ -332,15 +330,6 @@ export class PostForm extends Component { - - - - -
{!this.props.post && ( @@ -420,20 +409,6 @@ export class PostForm extends Component { ); } - setupEmojiPicker() { - emojiPicker.on('emoji', twemojiHtmlStr => { - if (this.state.postForm.body == null) { - this.state.postForm.body = ''; - } - var el = document.createElement('div'); - el.innerHTML = twemojiHtmlStr; - let nativeUnicode = (el.childNodes[0] as HTMLElement).getAttribute('alt'); - let shortName = `:${emojiShortName[nativeUnicode]}:`; - this.state.postForm.body += shortName; - this.setState(this.state); - }); - } - handlePostSubmit(i: PostForm, event: any) { event.preventDefault(); @@ -596,10 +571,6 @@ export class PostForm extends Component { }); } - handleEmojiPickerClick(_i: PostForm, event: any) { - emojiPicker.togglePicker(event.target); - } - parseMessage(msg: WebSocketJsonResponse) { let res = wsJsonToRes(msg); if (msg.error) { diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 3b077794..b3d0f368 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -51,11 +51,9 @@ import Tribute from 'tributejs/src/Tribute.js'; import markdown_it from 'markdown-it'; import markdownitEmoji from 'markdown-it-emoji/light'; import markdown_it_container from 'markdown-it-container'; -import twemoji from 'twemoji'; import emojiShortName from 'emoji-short-name'; import Toastify from 'toastify-js'; import tippy from 'tippy.js'; -import EmojiButton from '@joeattardi/emoji-button'; export const repoUrl = 'https://github.com/LemmyNet/lemmy'; export const helpGuideUrl = '/docs/about_guide.html'; @@ -114,14 +112,6 @@ export const themes = [ 'litely', ]; -export const emojiPicker = new EmojiButton({ - // Use the emojiShortName from native - style: 'twemoji', - theme: 'dark', - position: 'auto-start', - // TODO i18n -}); - const DEFAULT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; @@ -178,10 +168,6 @@ export const md = new markdown_it({ defs: objectFlip(emojiShortName), }); -md.renderer.rules.emoji = function (token, idx) { - return twemoji.parse(token[idx].content); -}; - export function hotRankComment(comment: Comment): number { return hotRank(comment.score, comment.published); } @@ -590,8 +576,7 @@ export function setupTribute(): Tribute { trigger: ':', menuItemTemplate: (item: any) => { let shortName = `:${item.original.key}:`; - let twemojiIcon = twemoji.parse(item.original.val); - return `${twemojiIcon} ${shortName}`; + return `${item.original.val} ${shortName}`; }, selectTemplate: (item: any) => { return `:${item.original.key}:`; diff --git a/ui/yarn.lock b/ui/yarn.lock index 076083fb..aa8ef7d4 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -359,32 +359,6 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@fortawesome/fontawesome-common-types@^0.2.28": - version "0.2.28" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.28.tgz#1091bdfe63b3f139441e9cba27aa022bff97d8b2" - integrity sha512-gtis2/5yLdfI6n0ia0jH7NJs5i/Z/8M/ZbQL6jXQhCthEOe5Cr5NcQPhgTvFxNOtURE03/ZqUcEskdn2M+QaBg== - -"@fortawesome/fontawesome-svg-core@^1.2.22": - version "1.2.28" - resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.28.tgz#e5b8c8814ef375f01f5d7c132d3c3a2f83a3abf9" - integrity sha512-4LeaNHWvrneoU0i8b5RTOJHKx7E+y7jYejplR7uSVB34+mp3Veg7cbKk7NBCLiI4TyoWS1wh9ZdoyLJR8wSAdg== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.28" - -"@fortawesome/free-regular-svg-icons@^5.10.2": - version "5.13.0" - resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.13.0.tgz#925a13d8bdda0678f71551828cac80ab47b8150c" - integrity sha512-70FAyiS5j+ANYD4dh9NGowTorNDnyvQHHpCM7FpnF7GxtDjBUCKdrFqCPzesEIpNDFNd+La3vex+jDk4nnUfpA== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.28" - -"@fortawesome/free-solid-svg-icons@^5.10.2": - version "5.13.0" - resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.13.0.tgz#44d9118668ad96b4fd5c9434a43efc5903525739" - integrity sha512-IHUgDJdomv6YtG4p3zl1B5wWf9ffinHIvebqQOmV3U+3SLw4fC+LUCCgwfETkbTtjy5/Qws2VoVf6z/ETQpFpg== - dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.28" - "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" @@ -557,25 +531,6 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" -"@joeattardi/emoji-button@^2.12.1": - version "2.12.1" - resolved "https://registry.yarnpkg.com/@joeattardi/emoji-button/-/emoji-button-2.12.1.tgz#190df7c00721e04742ed6f8852db828798a4cf98" - integrity sha512-rUuCXIcv4mRFK2IUKarYJN6J667wtH234smb1aQILzRf3/ycOoa6yUwnnvjxZeXMsPhuTnz15ndMOP2DhO5nNw== - dependencies: - "@fortawesome/fontawesome-svg-core" "^1.2.22" - "@fortawesome/free-regular-svg-icons" "^5.10.2" - "@fortawesome/free-solid-svg-icons" "^5.10.2" - "@popperjs/core" "^2.0.0" - focus-trap "^5.1.0" - tiny-emitter "^2.1.0" - tslib "^1.10.0" - twemoji "^12.1.5" - -"@popperjs/core@^2.0.0": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.2.3.tgz#0ae22b5650ab0b8fe508047245b66e71fc59e983" - integrity sha512-68EQPzEZRrpFavFX40V2+80eqzQIhgza2AGTXW+i8laxSA4It+Y13rmZInrAYoIujp8YO7YJPbvgOesDZcIulQ== - "@popperjs/core@^2.2.0": version "2.3.2" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.3.2.tgz#1e56eb99bccddbda6a3e29aa4f3660f5b23edc43" @@ -2660,14 +2615,6 @@ fliplog@^0.3.13: dependencies: chain-able "^1.0.1" -focus-trap@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-5.1.0.tgz#64a0bfabd95c382103397dbc96bfef3a3cf8e5ad" - integrity sha512-CkB/nrO55069QAUjWFBpX6oc+9V90Qhgpe6fBWApzruMq5gnlh90Oo7iSSDK7pKiV5ugG6OY2AXM5mxcmL3lwQ== - dependencies: - tabbable "^4.0.0" - xtend "^4.0.1" - for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2729,15 +2676,6 @@ fs-extra@^7.0.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2909,7 +2847,7 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.3: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== @@ -4085,15 +4023,6 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" -jsonfile@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922" - integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w== - dependencies: - universalify "^0.1.2" - optionalDependencies: - graceful-fs "^4.1.6" - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -6164,11 +6093,6 @@ symbol-tree@^3.2.2: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -tabbable@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-4.0.0.tgz#5bff1d1135df1482cf0f0206434f15eadbeb9261" - integrity sha512-H1XoH1URcBOa/rZZWxLxHCtOdVUEev+9vo5YdYhC9tCY4wnybX+VQrCYuy9ubkg69fCBxCONJOSLGfw0DWMffQ== - table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -6220,11 +6144,6 @@ through@^2.3.6: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -tiny-emitter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" - integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== - tiny-invariant@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" @@ -6376,11 +6295,6 @@ ts-transform-inferno@^4.0.3: resolved "https://registry.yarnpkg.com/ts-transform-inferno/-/ts-transform-inferno-4.0.3.tgz#2cc0eb125abdaff24b8298106a618ab7c6319edc" integrity sha512-Pcg0PVQwJ7Fpv4+3R9obFNsrNKQyLbmUqsjeG7T7r4/4UTgIl0MSwurexjtuGpCp2iv2X/i9ffKPAfAOyYJ9og== -tslib@^1.10.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== - tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" @@ -6405,21 +6319,6 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -twemoji-parser@12.1.3: - version "12.1.3" - resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-12.1.3.tgz#916c0153e77bd5f1011e7a99cbeacf52e43c9371" - integrity sha512-ND4LZXF4X92/PFrzSgGkq6KPPg8swy/U0yRw1k/+izWRVmq1HYi3khPwV3XIB6FRudgVICAaBhJfW8e8G3HC7Q== - -twemoji@^12.1.2, twemoji@^12.1.5: - version "12.1.5" - resolved "https://registry.yarnpkg.com/twemoji/-/twemoji-12.1.5.tgz#a961fb65a1afcb1f729ad7e59391f9fe969820b9" - integrity sha512-B0PBVy5xomwb1M/WZxf/IqPZfnoIYy1skXnlHjMwLwTNfZ9ljh8VgWQktAPcJXu8080WoEh6YwQGPVhDVqvrVQ== - dependencies: - fs-extra "^8.0.1" - jsonfile "^5.0.0" - twemoji-parser "12.1.3" - universalify "^0.1.2" - type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -6505,7 +6404,7 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -universalify@^0.1.0, universalify@^0.1.2: +universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== @@ -6761,11 +6660,6 @@ xregexp@^4.3.0: dependencies: "@babel/runtime-corejs3" "^7.8.3" -xtend@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" From 5b719a03bf4e9ca56ede29ef6bfb007b1c95c76e Mon Sep 17 00:00:00 2001 From: Filip Djuricic Date: Thu, 9 Jul 2020 20:32:44 +0000 Subject: [PATCH 09/47] Translated using Weblate (Serbian (latin)) Currently translated at 26.8% (67 of 250 strings) Translation: Lemmy/lemmy Translate-URL: http://weblate.yerbamate.dev/projects/lemmy/lemmy/sr_Latn/ --- ui/translations/sr_Latn.json | 74 +++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/ui/translations/sr_Latn.json b/ui/translations/sr_Latn.json index 0967ef42..12a38884 100644 --- a/ui/translations/sr_Latn.json +++ b/ui/translations/sr_Latn.json @@ -1 +1,73 @@ -{} +{ + "password": "Lozinka", + "verify_password": "Potvrdite Loziku", + "old_password": "Stara Lozinka", + "reset_password_mail_sent": "Poslali smo Vam email za promenu lozinke.", + "private_message_disclaimer": "Napomena: Privatne poruke poslate putem Lemmy-a nisu osigurane. Molimo vas napravite nalog na <1>Riot.im za bezbednu razmenu poruka.", + "browser_default": "Podrazumevano od strane pretraživača", + "number_of_upvotes_0": "{{count}} Gore-glas", + "number_of_upvotes_1": "{{count}} Gore-glasova", + "number_of_upvotes_2": "{{count}} Gore-glasa", + "subscribe_to_communities": "Pretplatite se nekim <1>zajednicama.", + "show_nsfw": "Prikaži NSFW sadržaj", + "sponsor_message": "Lemmy je besplatan, <1>softver otvorenog koda, bez reklamiranja, monetizovanja ili preduzetničkog kapitala, ikada. Vaše donacije direktno podržavaju aktivni razvoj projekta.Zahvaljujemo se sledećim ljudima:", + "donate_to_lemmy": "Donirajte Lemmy-u", + "general_sponsors": "Generalni Sponzori su oni koji su donirali između $10 i $39 Lemmy-u.", + "powered_by": "Sajt pokreće", + "forgot_password": "zaboravljena lozinka", + "password_change": "Promena Lozinke", + "new_password": "Nova Lozinka", + "no_email_setup": "Ovaj server nije pravilno namestio Vaš email.", + "email": "Email", + "matrix_user_id": "Korisnik Matrixa", + "send_notifications_to_email": "Primajte notifikacie na Vaš Email", + "optional": "Opcionalno", + "expires": "Ističe", + "language": "Jezik", + "downvotes_disabled": "Onemogućite negativne glasove", + "enable_downvotes": "Dozvolite negativne glasove", + "upvote": "Gore-glas", + "downvote": "Dole-glas", + "number_of_downvotes_0": "{{count}} Dole-glas", + "number_of_downvotes_1": "{{count}} Dole-glasova", + "number_of_downvotes_2": "{{count}} Dole-glasa", + "open_registration": "Otvorena Registracija", + "registration_closed": "Zatvorena registracija", + "enable_nsfw": "Dozvolite NSFW sadržaj", + "url": "URL", + "body": "Sadržaj", + "copy_suggested_title": "kopirajte predloženi naslov: {{title}}", + "community": "Zajednica", + "expand_here": "Proširite ovde", + "chat": "Ćaskanje", + "recent_comments": "Nedavni Komentari", + "no_results": "Nema rezultata.", + "setup": "Instalacioni proces", + "lemmy_instance_setup": "Instaliranje Lemmy Instance", + "setup_admin": "Napravite Administratorski Nalog", + "your_site": "Vaš sajt", + "modified": "izmenjeno", + "nsfw": "NSFW", + "theme": "Tema", + "sponsors": "Sponzori", + "sponsors_of_lemmy": "Sponzori Lemmy-a", + "support_on_patreon": "Podržite nas na Patreonu", + "support_on_liberapay": "Podržite nas na Liberpay-u", + "support_on_open_collective": "Podržite nas na OpenCollective", + "donate": "Donirajte", + "silver_sponsors": "Srebrni Sponzori su oni koji su donirali $40 Lemmy-u.", + "crypto": "Kripto", + "bitcoin": "Bitcoin", + "ethereum": "Ethereum", + "monero": "Monero", + "code": "Kod", + "joined": "Pridružio/la", + "by": "od", + "to": "do", + "from": "od", + "transfer_community": "transferujte zajednicu", + "transfer_site": "transferujte sajt", + "are_you_sure": "da li ste sigurni?", + "yes": "da", + "no": "ne" +} From d222c60cef289b57f0ce350e9f24ce2df4792ef5 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Jul 2020 19:59:02 -0400 Subject: [PATCH 10/47] A few cake day fixes. #916 --- server/src/db/comment_view.rs | 6 ++--- ui/src/components/cake-day.tsx | 15 +++++-------- ui/src/components/comment-node.tsx | 7 +----- ui/src/components/post-listing.tsx | 7 +----- ui/src/components/user-listing.tsx | 35 ++++++++++++++++++++---------- ui/src/utils.ts | 4 ++-- 6 files changed, 35 insertions(+), 39 deletions(-) diff --git a/server/src/db/comment_view.rs b/server/src/db/comment_view.rs index 75ed4cb7..7c853a81 100644 --- a/server/src/db/comment_view.rs +++ b/server/src/db/comment_view.rs @@ -27,8 +27,8 @@ table! { creator_actor_id -> Text, creator_local -> Bool, creator_name -> Varchar, - creator_avatar -> Nullable, creator_published -> Timestamp, + creator_avatar -> Nullable, score -> BigInt, upvotes -> BigInt, downvotes -> BigInt, @@ -63,8 +63,8 @@ table! { creator_actor_id -> Text, creator_local -> Bool, creator_name -> Varchar, - creator_avatar -> Nullable, creator_published -> Timestamp, + creator_avatar -> Nullable, score -> BigInt, upvotes -> BigInt, downvotes -> BigInt, @@ -102,8 +102,8 @@ pub struct CommentView { pub creator_actor_id: String, pub creator_local: bool, pub creator_name: String, - pub creator_avatar: Option, pub creator_published: chrono::NaiveDateTime, + pub creator_avatar: Option, pub score: i64, pub upvotes: i64, pub downvotes: i64, diff --git a/ui/src/components/cake-day.tsx b/ui/src/components/cake-day.tsx index be807184..f28be33c 100644 --- a/ui/src/components/cake-day.tsx +++ b/ui/src/components/cake-day.tsx @@ -2,20 +2,15 @@ import { Component } from 'inferno'; import { i18n } from '../i18next'; interface CakeDayProps { - creator_name: string; - is_post_creator?: boolean; + creatorName: string; } export class CakeDay extends Component { render() { - const { creator_name, is_post_creator } = this.props; - return (
@@ -24,7 +19,7 @@ export class CakeDay extends Component { ); } - cakeDayTippy(creator_name: string): string { - return i18n.t('cake_day_info', { creator_name }); + cakeDayTippy(): string { + return i18n.t('cake_day_info', { creator_name: this.props.creatorName }); } } diff --git a/ui/src/components/comment-node.tsx b/ui/src/components/comment-node.tsx index 0e2d1d94..8e976e7c 100644 --- a/ui/src/components/comment-node.tsx +++ b/ui/src/components/comment-node.tsx @@ -26,7 +26,6 @@ import { isMod, setupTippy, colorList, - isCakeDay, } from '../utils'; import moment from 'moment'; import { MomentTime } from './moment-time'; @@ -34,7 +33,6 @@ import { CommentForm } from './comment-form'; import { CommentNodes } from './comment-nodes'; import { UserListing } from './user-listing'; import { i18n } from '../i18next'; -import { CakeDay } from './cake-day'; interface CommentNodeState { showReply: boolean; @@ -160,14 +158,11 @@ export class CommentNode extends Component { id: node.comment.creator_id, local: node.comment.creator_local, actor_id: node.comment.creator_actor_id, + published: node.comment.creator_published, }} /> - {isCakeDay(node.comment.creator_published) && ( - - )} - {this.isMod && (
{i18n.t('mod')} diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx index 92a2f9cb..fa2a078e 100644 --- a/ui/src/components/post-listing.tsx +++ b/ui/src/components/post-listing.tsx @@ -33,10 +33,8 @@ import { setupTippy, hostname, previewLines, - isCakeDay, } from '../utils'; import { i18n } from '../i18next'; -import { CakeDay } from './cake-day'; interface PostListingState { showEdit: boolean; @@ -436,13 +434,10 @@ export class PostListing extends Component { id: post.creator_id, local: post.creator_local, actor_id: post.creator_actor_id, + published: post.creator_published, }} /> - {isCakeDay(post.creator_published) && ( - - )} - {this.isMod && ( {i18n.t('mod')} diff --git a/ui/src/components/user-listing.tsx b/ui/src/components/user-listing.tsx index 0e150b94..58475d3e 100644 --- a/ui/src/components/user-listing.tsx +++ b/ui/src/components/user-listing.tsx @@ -1,7 +1,13 @@ import { Component } from 'inferno'; import { Link } from 'inferno-router'; import { UserView } from '../interfaces'; -import { pictrsAvatarThumbnail, showAvatars, hostname } from '../utils'; +import { + pictrsAvatarThumbnail, + showAvatars, + hostname, + isCakeDay, +} from '../utils'; +import { CakeDay } from './cake-day'; interface UserOther { name: string; @@ -9,6 +15,7 @@ interface UserOther { avatar?: string; local?: boolean; actor_id?: string; + published?: string; } interface UserListingProps { @@ -35,17 +42,21 @@ export class UserListing extends Component { } return ( - - {user.avatar && showAvatars() && ( - - )} - {name_} - + <> + + {user.avatar && showAvatars() && ( + + )} + {name_} + + + {isCakeDay(user.published) && } + ); } } diff --git a/ui/src/utils.ts b/ui/src/utils.ts index e38834aa..22536043 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -502,10 +502,10 @@ export function showAvatars(): boolean { ); } -export function isCakeDay(creator_published: string): boolean { +export function isCakeDay(published: string): boolean { // moment(undefined) or moment.utc(undefined) returns the current date/time // moment(null) or moment.utc(null) returns null - const userCreationDate = moment.utc(creator_published || null).local(); + const userCreationDate = moment.utc(published || null).local(); const currentDate = moment(new Date()); return ( From 85c07e7154c82e5b387bb6a02aae70645cf1d8e0 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Jul 2020 20:03:33 -0400 Subject: [PATCH 11/47] Correctly hide next / prev in paginators. Fixes #914 (#927) --- ui/src/components/communities.tsx | 2 +- ui/src/components/community.tsx | 2 +- ui/src/components/inbox.tsx | 32 ++++++++++++++++++------------- ui/src/components/main.tsx | 2 +- ui/src/components/search.tsx | 30 ++++++++++++++--------------- ui/src/components/user.tsx | 14 ++++++++------ 6 files changed, 45 insertions(+), 37 deletions(-) diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index 441f7bb1..10a3ab80 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -160,7 +160,7 @@ export class Communities extends Component { )} - {this.state.communities.length == communityLimit && ( + {this.state.communities.length > 0 && ( )} - {this.state.posts.length == fetchLimit && ( + {this.state.posts.length > 0 && ( )} - + {this.unreadCount() > 0 && ( + + )}
); } @@ -534,15 +536,19 @@ export class Inbox extends Component { } sendUnreadCount() { - let count = - this.state.replies.filter(r => !r.read).length + - this.state.mentions.filter(r => !r.read).length + - this.state.messages.filter( - r => !r.read && r.creator_id !== UserService.Instance.user.id - ).length; - UserService.Instance.user.unreadCount = count; + UserService.Instance.user.unreadCount = this.unreadCount(); UserService.Instance.sub.next({ user: UserService.Instance.user, }); } + + unreadCount(): number { + return ( + this.state.replies.filter(r => !r.read).length + + this.state.mentions.filter(r => !r.read).length + + this.state.messages.filter( + r => !r.read && r.creator_id !== UserService.Instance.user.id + ).length + ); + } } diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 9e9027d6..9063a039 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -497,7 +497,7 @@ export class Main extends Component { {i18n.t('prev')} )} - {this.state.posts.length == fetchLimit && ( + {this.state.posts.length > 0 && (
); @@ -383,26 +383,26 @@ export class Search extends Component { {i18n.t('prev')} )} - + + {this.resultsCount() > 0 && ( + + )}
); } - noResults() { + resultsCount(): number { let res = this.state.searchResponse; return ( -
- {res && - res.posts.length == 0 && - res.comments.length == 0 && - res.communities.length == 0 && - res.users.length == 0 && {i18n.t('no_results')}} -
+ res.posts.length + + res.comments.length + + res.communities.length + + res.users.length ); } diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index 7e679ed1..af72a397 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.tsx @@ -893,12 +893,14 @@ export class User extends Component { {i18n.t('prev')} )} - + {this.state.comments.length + this.state.posts.length > 0 && ( + + )}
); } From 50e6d81d0b40e1d9caa0db83d20026adf3aef631 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Thu, 9 Jul 2020 20:03:47 -0400 Subject: [PATCH 12/47] Redirect to login page for votes, comments, pages, etc. Fixes #849 (#926) --- ui/src/components/comment-form.tsx | 255 ++++++++++--------- ui/src/components/create-community.tsx | 7 +- ui/src/components/create-post.tsx | 7 +- ui/src/components/create-private-message.tsx | 7 +- ui/src/components/post-listing.tsx | 9 + ui/translations/en.json | 1 + 6 files changed, 164 insertions(+), 122 deletions(-) diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index 32bc3786..a433dbd4 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -1,4 +1,5 @@ import { Component, linkEvent } from 'inferno'; +import { Link } from 'inferno-router'; import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; import { Prompt } from 'inferno-router'; @@ -25,6 +26,7 @@ import autosize from 'autosize'; import Tribute from 'tributejs/src/Tribute.js'; import emojiShortName from 'emoji-short-name'; import { i18n } from '../i18next'; +import { T } from 'inferno-i18next'; interface CommentFormProps { postId?: number; @@ -99,29 +101,31 @@ export class CommentForm extends Component { componentDidMount() { let textarea: any = document.getElementById(this.id); - autosize(textarea); - this.tribute.attach(textarea); - textarea.addEventListener('tribute-replaced', () => { - this.state.commentForm.content = textarea.value; - this.setState(this.state); - autosize.update(textarea); - }); + if (textarea) { + autosize(textarea); + this.tribute.attach(textarea); + textarea.addEventListener('tribute-replaced', () => { + this.state.commentForm.content = textarea.value; + this.setState(this.state); + autosize.update(textarea); + }); - // Quoting of selected text - let selectedText = window.getSelection().toString(); - if (selectedText) { - let quotedText = - selectedText - .split('\n') - .map(t => `> ${t}`) - .join('\n') + '\n\n'; - this.state.commentForm.content = quotedText; - this.setState(this.state); - // Not sure why this needs a delay - setTimeout(() => autosize.update(textarea), 10); + // Quoting of selected text + let selectedText = window.getSelection().toString(); + if (selectedText) { + let quotedText = + selectedText + .split('\n') + .map(t => `> ${t}`) + .join('\n') + '\n\n'; + this.state.commentForm.content = quotedText; + this.setState(this.state); + // Not sure why this needs a delay + setTimeout(() => autosize.update(textarea), 10); + } + + textarea.focus(); } - - textarea.focus(); } componentDidUpdate() { @@ -144,115 +148,128 @@ export class CommentForm extends Component { when={this.state.commentForm.content} message={i18n.t('block_leaving')} /> -
-
-
-