diff options
author | Dessalines <tyhou13@gmx.com> | 2020-01-31 20:02:20 -0500 |
---|---|---|
committer | Dessalines <tyhou13@gmx.com> | 2020-01-31 20:02:20 -0500 |
commit | 8036474ddad2f20c27a2fb023395306d6b9e577d (patch) | |
tree | 28f3546c9086931f33d9ee6d910c9aa43a5a1f77 /ui | |
parent | 5188bddd4ddb1d4f4bc4add24db210789054c2a5 (diff) |
Starting to work on user message scope.
Diffstat (limited to 'ui')
-rw-r--r-- | ui/src/components/community.tsx | 55 | ||||
-rw-r--r-- | ui/src/components/inbox.tsx | 1 | ||||
-rw-r--r-- | ui/src/components/main.tsx | 105 | ||||
-rw-r--r-- | ui/src/components/navbar.tsx | 53 | ||||
-rw-r--r-- | ui/src/components/post.tsx | 11 | ||||
-rw-r--r-- | ui/src/components/sidebar.tsx | 17 | ||||
-rw-r--r-- | ui/src/interfaces.ts | 11 | ||||
-rw-r--r-- | ui/src/services/WebSocketService.ts | 5 | ||||
-rw-r--r-- | ui/yarn.lock | 503 |
9 files changed, 534 insertions, 227 deletions
diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 3c5f6890..a88ec952 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -14,20 +14,17 @@ import { GetCommunityForm, ListingType, GetPostsResponse, + PostResponse, CreatePostLikeResponse, + AddModToCommunityResponse, + BanFromCommunityResponse, WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; import { PostListings } from './post-listings'; import { SortSelect } from './sort-select'; import { Sidebar } from './sidebar'; -import { - wsJsonToRes, - routeSortTypeToEnum, - fetchLimit, - postRefetchSeconds, - toast, -} from '../utils'; +import { wsJsonToRes, routeSortTypeToEnum, fetchLimit, toast } from '../utils'; import { T } from 'inferno-i18next'; import { i18n } from '../i18next'; @@ -37,6 +34,7 @@ interface State { communityName: string; moderators: Array<CommunityUser>; admins: Array<UserView>; + online: number; loading: boolean; posts: Array<Post>; sort: SortType; @@ -67,6 +65,7 @@ export class Community extends Component<any, State> { admins: [], communityId: Number(this.props.match.params.id), communityName: this.props.match.params.name, + online: null, loading: true, posts: [], sort: this.getSortTypeFromProps(this.props), @@ -158,6 +157,7 @@ export class Community extends Component<any, State> { community={this.state.community} moderators={this.state.moderators} admins={this.state.admins} + online={this.state.online} /> </div> </div> @@ -240,11 +240,6 @@ export class Community extends Component<any, State> { ); } - keepFetchingPosts() { - this.fetchPosts(); - this.postFetcher = setInterval(() => this.fetchPosts(), postRefetchSeconds); - } - fetchPosts() { let getPostsForm: GetPostsForm = { page: this.state.page, @@ -268,9 +263,10 @@ export class Community extends Component<any, State> { this.state.community = data.community; this.state.moderators = data.moderators; this.state.admins = data.admins; + this.state.online = data.online; document.title = `/c/${this.state.community.name} - ${WebSocketService.Instance.site.name}`; this.setState(this.state); - this.keepFetchingPosts(); + this.fetchPosts(); } else if (res.op == UserOperation.EditCommunity) { let data = res.data as CommunityResponse; this.state.community = data.community; @@ -286,13 +282,44 @@ export class Community extends Component<any, State> { this.state.posts = data.posts; this.state.loading = false; this.setState(this.state); + } else if (res.op == UserOperation.EditPost) { + let data = res.data as PostResponse; + let found = this.state.posts.find(c => c.id == data.post.id); + + found.url = data.post.url; + found.name = data.post.name; + found.nsfw = data.post.nsfw; + + this.setState(this.state); + } else if (res.op == UserOperation.CreatePost) { + let data = res.data as PostResponse; + this.state.posts.unshift(data.post); + this.setState(this.state); } else if (res.op == UserOperation.CreatePostLike) { let data = res.data as CreatePostLikeResponse; let found = this.state.posts.find(c => c.id == data.post.id); - found.my_vote = data.post.my_vote; + found.score = data.post.score; found.upvotes = data.post.upvotes; found.downvotes = data.post.downvotes; + if (data.post.my_vote !== null) { + found.my_vote = data.post.my_vote; + found.upvoteLoading = false; + found.downvoteLoading = false; + } + + this.setState(this.state); + } else if (res.op == UserOperation.AddModToCommunity) { + let data = res.data as AddModToCommunityResponse; + this.state.moderators = data.moderators; + this.setState(this.state); + } else if (res.op == UserOperation.BanFromCommunity) { + let data = res.data as BanFromCommunityResponse; + + this.state.posts + .filter(p => p.creator_id == data.user.id) + .forEach(p => (p.banned = data.banned)); + this.setState(this.state); } } diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx index 41c1ce60..5585d84f 100644 --- a/ui/src/components/inbox.tsx +++ b/ui/src/components/inbox.tsx @@ -422,6 +422,7 @@ export class Inbox extends Component<any, InboxState> { this.setState(this.state); } else if (res.op == UserOperation.CreateComment) { // let res: CommentResponse = msg; + // TODO gotta remove this toast(i18n.t('reply_sent')); // this.state.replies.unshift(res.comment); // TODO do this right // this.setState(this.state); diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 6bf4164f..9ff6af44 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -15,8 +15,11 @@ import { SiteResponse, GetPostsResponse, CreatePostLikeResponse, + PostResponse, Post, GetPostsForm, + AddAdminResponse, + BanUserResponse, WebSocketJsonResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; @@ -31,7 +34,6 @@ import { fetchLimit, routeSortTypeToEnum, routeListingTypeToEnum, - postRefetchSeconds, pictshareAvatarThumbnail, showAvatars, toast, @@ -42,7 +44,7 @@ import { T } from 'inferno-i18next'; interface MainState { subscribedCommunities: Array<CommunityUser>; trendingCommunities: Array<Community>; - site: GetSiteResponse; + siteRes: GetSiteResponse; showEditSite: boolean; loading: boolean; posts: Array<Post>; @@ -53,11 +55,10 @@ interface MainState { export class Main extends Component<any, MainState> { private subscription: Subscription; - private postFetcher: any; private emptyState: MainState = { subscribedCommunities: [], trendingCommunities: [], - site: { + siteRes: { site: { id: null, name: null, @@ -133,12 +134,11 @@ export class Main extends Component<any, MainState> { WebSocketService.Instance.listCommunities(listCommunitiesForm); - this.keepFetchingPosts(); + this.fetchPosts(); } componentWillUnmount() { this.subscription.unsubscribe(); - clearInterval(this.postFetcher); } // Necessary for back button for some reason @@ -241,7 +241,7 @@ export class Main extends Component<any, MainState> { this.siteInfo() ) : ( <SiteForm - site={this.state.site.site} + site={this.state.siteRes.site} onCancel={this.handleEditCancel} /> )} @@ -262,7 +262,7 @@ export class Main extends Component<any, MainState> { <div> <div class="card border-secondary mb-3"> <div class="card-body"> - <h5 class="mb-0">{`${this.state.site.site.name}`}</h5> + <h5 class="mb-0">{`${this.state.siteRes.site.name}`}</h5> {this.canAdmin && ( <ul class="list-inline mb-1 text-muted small font-weight-bold"> <li className="list-inline-item"> @@ -279,7 +279,7 @@ export class Main extends Component<any, MainState> { <li className="list-inline-item badge badge-secondary"> <T i18nKey="number_online" - interpolation={{ count: this.state.site.online }} + interpolation={{ count: this.state.siteRes.online }} > # </T> @@ -288,7 +288,7 @@ export class Main extends Component<any, MainState> { <T i18nKey="number_of_users" interpolation={{ - count: this.state.site.site.number_of_users, + count: this.state.siteRes.site.number_of_users, }} > # @@ -298,7 +298,7 @@ export class Main extends Component<any, MainState> { <T i18nKey="number_of_communities" interpolation={{ - count: this.state.site.site.number_of_communities, + count: this.state.siteRes.site.number_of_communities, }} > # @@ -308,7 +308,7 @@ export class Main extends Component<any, MainState> { <T i18nKey="number_of_posts" interpolation={{ - count: this.state.site.site.number_of_posts, + count: this.state.siteRes.site.number_of_posts, }} > # @@ -318,7 +318,7 @@ export class Main extends Component<any, MainState> { <T i18nKey="number_of_comments" interpolation={{ - count: this.state.site.site.number_of_comments, + count: this.state.siteRes.site.number_of_comments, }} > # @@ -337,7 +337,7 @@ export class Main extends Component<any, MainState> { </T> : </li> - {this.state.site.admins.map(admin => ( + {this.state.siteRes.admins.map(admin => ( <li class="list-inline-item"> <Link class="text-info" to={`/u/${admin.name}`}> {admin.avatar && showAvatars() && ( @@ -355,13 +355,13 @@ export class Main extends Component<any, MainState> { </ul> </div> </div> - {this.state.site.site.description && ( + {this.state.siteRes.site.description && ( <div class="card border-secondary mb-3"> <div class="card-body"> <div className="md-div" dangerouslySetInnerHTML={mdToHtml( - this.state.site.site.description + this.state.siteRes.site.description )} /> </div> @@ -494,7 +494,7 @@ export class Main extends Component<any, MainState> { get canAdmin(): boolean { return ( UserService.Instance.user && - this.state.site.admins + this.state.siteRes.admins .map(a => a.id) .includes(UserService.Instance.user.id) ); @@ -548,11 +548,6 @@ export class Main extends Component<any, MainState> { window.scrollTo(0, 0); } - keepFetchingPosts() { - this.fetchPosts(); - this.postFetcher = setInterval(() => this.fetchPosts(), postRefetchSeconds); - } - fetchPosts() { let getPostsForm: GetPostsForm = { page: this.state.page, @@ -584,15 +579,15 @@ export class Main extends Component<any, MainState> { if (!data.site) { this.context.router.history.push('/setup'); } - this.state.site.admins = data.admins; - this.state.site.site = data.site; - this.state.site.banned = data.banned; - this.state.site.online = data.online; + this.state.siteRes.admins = data.admins; + this.state.siteRes.site = data.site; + this.state.siteRes.banned = data.banned; + this.state.siteRes.online = data.online; this.setState(this.state); document.title = `${WebSocketService.Instance.site.name}`; } else if (res.op == UserOperation.EditSite) { let data = res.data as SiteResponse; - this.state.site.site = data.site; + this.state.siteRes.site = data.site; this.state.showEditSite = false; this.setState(this.state); } else if (res.op == UserOperation.GetPosts) { @@ -600,13 +595,67 @@ export class Main extends Component<any, MainState> { this.state.posts = data.posts; this.state.loading = false; this.setState(this.state); + } else if (res.op == UserOperation.CreatePost) { + let data = res.data as PostResponse; + + // If you're on subscribed, only push it if you're subscribed. + if (this.state.type_ == ListingType.Subscribed) { + if ( + this.state.subscribedCommunities + .map(c => c.community_id) + .includes(data.post.community_id) + ) { + this.state.posts.unshift(data.post); + } + } else { + this.state.posts.unshift(data.post); + } + + this.setState(this.state); + } else if (res.op == UserOperation.EditPost) { + let data = res.data as PostResponse; + let found = this.state.posts.find(c => c.id == data.post.id); + + found.url = data.post.url; + found.name = data.post.name; + found.nsfw = data.post.nsfw; + + this.setState(this.state); } else if (res.op == UserOperation.CreatePostLike) { let data = res.data as CreatePostLikeResponse; let found = this.state.posts.find(c => c.id == data.post.id); - found.my_vote = data.post.my_vote; + found.score = data.post.score; found.upvotes = data.post.upvotes; found.downvotes = data.post.downvotes; + if (data.post.my_vote !== null) { + found.my_vote = data.post.my_vote; + found.upvoteLoading = false; + found.downvoteLoading = false; + } + + this.setState(this.state); + } else if (res.op == UserOperation.AddAdmin) { + let data = res.data as AddAdminResponse; + this.state.siteRes.admins = data.admins; + this.setState(this.state); + } else if (res.op == UserOperation.BanUser) { + let data = res.data as BanUserResponse; + let found = this.state.siteRes.banned.find(u => (u.id = data.user.id)); + + // Remove the banned if its found in the list, and the action is an unban + if (found && !data.banned) { + this.state.siteRes.banned = this.state.siteRes.banned.filter( + i => i.id !== data.user.id + ); + } else { + this.state.siteRes.banned.push(data.user); + } + + this.state.posts + .filter(p => p.creator_id == data.user.id) + .forEach(p => (p.banned = data.banned)); + this.setState(this.state); } } diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 1828fce9..d433ad1f 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -14,6 +14,7 @@ import { SortType, GetSiteResponse, Comment, + CommentResponse, PrivateMessage, WebSocketJsonResponse, } from '../interfaces'; @@ -58,7 +59,7 @@ export class Navbar extends Component<any, NavbarState> { super(props, context); this.state = this.emptyState; - this.keepFetchingUnreads(); + this.fetchUnreads(); // Subscribe to user changes this.userSub = UserService.Instance.sub.subscribe(user => { @@ -211,13 +212,6 @@ export class Navbar extends Component<any, NavbarState> { } else if (res.op == UserOperation.GetReplies) { let data = res.data as GetRepliesResponse; let unreadReplies = data.replies.filter(r => !r.read); - if ( - unreadReplies.length > 0 && - this.state.fetchCount > 1 && - JSON.stringify(this.state.replies) !== JSON.stringify(unreadReplies) - ) { - this.notify(unreadReplies); - } this.state.replies = unreadReplies; this.setState(this.state); @@ -225,13 +219,6 @@ export class Navbar extends Component<any, NavbarState> { } else if (res.op == UserOperation.GetUserMentions) { let data = res.data as GetUserMentionsResponse; let unreadMentions = data.mentions.filter(r => !r.read); - if ( - unreadMentions.length > 0 && - this.state.fetchCount > 1 && - JSON.stringify(this.state.mentions) !== JSON.stringify(unreadMentions) - ) { - this.notify(unreadMentions); - } this.state.mentions = unreadMentions; this.setState(this.state); @@ -239,17 +226,19 @@ export class Navbar extends Component<any, NavbarState> { } else if (res.op == UserOperation.GetPrivateMessages) { let data = res.data as PrivateMessagesResponse; let unreadMessages = data.messages.filter(r => !r.read); - if ( - unreadMessages.length > 0 && - this.state.fetchCount > 1 && - JSON.stringify(this.state.messages) !== JSON.stringify(unreadMessages) - ) { - this.notify(unreadMessages); - } this.state.messages = unreadMessages; this.setState(this.state); this.sendUnreadCount(); + } else if (res.op == UserOperation.CreateComment) { + // TODO do private messages too + let data = res.data as CommentResponse; + + if (UserService.Instance.user) { + if (data.recipient_ids.includes(UserService.Instance.user.id)) { + this.notify(data.comment); + } + } } else if (res.op == UserOperation.GetSite) { let data = res.data as GetSiteResponse; @@ -261,11 +250,6 @@ export class Navbar extends Component<any, NavbarState> { } } - keepFetchingUnreads() { - this.fetchUnreads(); - setInterval(() => this.fetchUnreads(), 15000); - } - fetchUnreads() { if (this.state.isLoggedIn) { let repliesForm: GetRepliesForm = { @@ -330,24 +314,23 @@ export class Navbar extends Component<any, NavbarState> { } } - notify(replies: Array<Comment | PrivateMessage>) { - let recentReply = replies[0]; + notify(reply: Comment | PrivateMessage) { if (Notification.permission !== 'granted') Notification.requestPermission(); else { var notification = new Notification( - `${replies.length} ${i18n.t('unread_messages')}`, + `${this.state.unreadCount} ${i18n.t('unread_messages')}`, { - icon: recentReply.creator_avatar - ? recentReply.creator_avatar + icon: reply.creator_avatar + ? reply.creator_avatar : `${window.location.protocol}//${window.location.host}/static/assets/apple-touch-icon.png`, - body: `${recentReply.creator_name}: ${recentReply.content}`, + body: `${reply.creator_name}: ${reply.content}`, } ); notification.onclick = () => { this.context.router.history.push( - isCommentType(recentReply) - ? `/post/${recentReply.post_id}/comment/${recentReply.id}` + isCommentType(reply) + ? `/post/${reply.post_id}/comment/${reply.id}` : `/inbox` ); }; diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 36621248..99a20b46 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -47,6 +47,7 @@ interface PostState { community: Community; moderators: Array<CommunityUser>; admins: Array<UserView>; + online: number; scrolled?: boolean; scrolled_comment_id?: number; loading: boolean; @@ -62,6 +63,7 @@ export class Post extends Component<any, PostState> { community: null, moderators: [], admins: [], + online: null, scrolled: false, loading: true, crossPosts: [], @@ -280,6 +282,7 @@ export class Post extends Component<any, PostState> { community={this.state.community} moderators={this.state.moderators} admins={this.state.admins} + online={this.state.online} /> </div> ); @@ -378,6 +381,7 @@ export class Post extends Component<any, PostState> { this.state.community = data.community; this.state.moderators = data.moderators; this.state.admins = data.admins; + this.state.online = data.online; this.state.loading = false; document.title = `${this.state.post.name} - ${WebSocketService.Instance.site.name}`; @@ -432,10 +436,15 @@ export class Post extends Component<any, PostState> { this.setState(this.state); } else if (res.op == UserOperation.CreatePostLike) { let data = res.data as CreatePostLikeResponse; - this.state.post.my_vote = data.post.my_vote; this.state.post.score = data.post.score; this.state.post.upvotes = data.post.upvotes; this.state.post.downvotes = data.post.downvotes; + if (data.post.my_vote !== null) { + this.state.post.my_vote = data.post.my_vote; + this.state.post.upvoteLoading = false; + this.state.post.downvoteLoading = false; + } + this.setState(this.state); } else if (res.op == UserOperation.EditPost) { let data = res.data as PostResponse; diff --git a/ui/src/components/sidebar.tsx b/ui/src/components/sidebar.tsx index 089dd558..0e6b68e6 100644 --- a/ui/src/components/sidebar.tsx +++ b/ui/src/components/sidebar.tsx @@ -22,6 +22,7 @@ interface SidebarProps { community: Community; moderators: Array<CommunityUser>; admins: Array<UserView>; + online: number; } interface SidebarState { @@ -156,10 +157,13 @@ export class Sidebar extends Component<SidebarProps, SidebarState> { </form> )} <ul class="my-1 list-inline"> - <li className="list-inline-item"> - <Link className="badge badge-secondary" to="/communities"> - {community.category_name} - </Link> + <li className="list-inline-item badge badge-secondary"> + <T + i18nKey="number_online" + interpolation={{ count: this.props.online }} + > + # + </T> </li> <li className="list-inline-item badge badge-secondary"> <T @@ -186,6 +190,11 @@ export class Sidebar extends Component<SidebarProps, SidebarState> { </T> </li> <li className="list-inline-item"> + <Link className="badge badge-secondary" to="/communities"> + {community.category_name} + </Link> + </li> + <li className="list-inline-item"> <Link className="badge badge-secondary" to={`/modlog/community/${this.props.community.id}`} diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts index bc4b8972..4036f7e6 100644 --- a/ui/src/interfaces.ts +++ b/ui/src/interfaces.ts @@ -539,6 +539,7 @@ export interface GetCommunityResponse { community: Community; moderators: Array<CommunityUser>; admins: Array<UserView>; + online: number; } export interface CommunityResponse { @@ -595,6 +596,7 @@ export interface GetPostResponse { community: Community; moderators: Array<CommunityUser>; admins: Array<UserView>; + online: number; } export interface SavePostForm { @@ -628,6 +630,7 @@ export interface SaveCommentForm { export interface CommentResponse { comment: Comment; + recipient_ids: Array<number>; } export interface CommentLikeForm { @@ -776,6 +779,14 @@ export interface PrivateMessageResponse { message: PrivateMessage; } +export interface UserJoinForm { + auth: string; +} + +export interface UserJoinResponse { + user_id: number; +} + export type MessageType = | EditPrivateMessageForm | LoginForm diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index 3ad0de44..f3d40149 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -38,6 +38,7 @@ import { PrivateMessageForm, EditPrivateMessageForm, GetPrivateMessagesForm, + UserJoinForm, MessageType, } from '../interfaces'; import { webSocket } from 'rxjs/webSocket'; @@ -73,6 +74,7 @@ export class WebSocketService { console.log(`Connected to ${wsUri}`); if (UserService.Instance.user) { + this.userJoin(); } } @@ -81,7 +83,8 @@ export class WebSocketService { } public userJoin() { - this.wsSendWrapper(UserOperation.ListCategories, undefined); + let form: UserJoinForm = { auth: UserService.Instance.auth }; + this.subject.next(this.wsSendWrapper(UserOperation.UserJoin, form)); } public login(loginForm: LoginForm) { diff --git a/ui/yarn.lock b/ui/yarn.lock index 4d09380b..2930764d 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -9,10 +9,10 @@ dependencies: "@babel/highlight" "^7.8.3" -"@babel/generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" - integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug== +"@babel/generator@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" + integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== dependencies: "@babel/types" "^7.8.3" jsesc "^2.5.1" @@ -51,23 +51,23 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" - integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== +"@babel/parser@^7.0.0", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" + integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== "@babel/runtime-corejs3@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.3.tgz#a2445836d0699e5ba77eea2c790ad9ea51e2cd27" - integrity sha512-lrIU4aVbmlM/wQPzhEvzvNJskKyYptuXb0fGC0lTQTupTOYtR2Vqbu6/jf8vTr4M8Wt1nIzxVrSvPI5qESa/xA== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.4.tgz#ccc4e042e2fae419c67fa709567e5d2179ed3940" + integrity sha512-+wpLqy5+fbQhvbllvlJEVRIpYj+COUWnnsm+I4jZlA8Lo7/MJmBhGTCHyk1/RWfOqBRJ2MbadddG6QltTKTlrg== dependencies: core-js-pure "^3.0.0" regenerator-runtime "^0.13.2" "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.3.tgz#0811944f73a6c926bb2ad35e918dcc1bfab279f1" - integrity sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308" + integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ== dependencies: regenerator-runtime "^0.13.2" @@ -81,15 +81,15 @@ "@babel/types" "^7.8.3" "@babel/traverse@^7.0.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" - integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" + integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.3" + "@babel/generator" "^7.8.4" "@babel/helper-function-name" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.3" + "@babel/parser" "^7.8.4" "@babel/types" "^7.8.3" debug "^4.1.0" globals "^11.1.0" @@ -170,9 +170,9 @@ "@types/linkify-it" "*" "@types/node@^13.5.0": - version "13.5.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.0.tgz#4e498dbf355795a611a87ae5ef811a8660d42662" - integrity sha512-Onhn+z72D2O2Pb2ql2xukJ55rglumsVo1H6Fmyi8mlU9SvKdBk/pUSUAiBY/d9bAOF7VVWajX3sths/+g6ZiAQ== + version "13.5.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.3.tgz#37f1f539b7535b9fb4ef77d59db1847a837b7f17" + integrity sha512-ZPnWX9PW992w6DUsz3JIXHaSb5v7qmKCVzC3km6SxcDGxk7zmLfYaCJTbktIa5NeywJkkZDhGldKqDIvC5DRrA== "@types/normalize-package-data@^2.4.0": version "2.4.0" @@ -189,49 +189,40 @@ resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== -"@typescript-eslint/eslint-plugin@2.16.0": - version "2.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.16.0.tgz#bf339b7db824c7cc3fd1ebedbc88dd17016471af" - integrity sha512-TKWbeFAKRPrvKiR9GNxErQ8sELKqg1ZvXi6uho07mcKShBnCnqNpDQWP01FEvWKf0bxM2g7uQEI5MNjSNqvUpQ== +"@typescript-eslint/eslint-plugin@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.18.0.tgz#f8cf272dfb057ecf1ea000fea1e0b3f06a32f9cb" + integrity sha512-kuO8WQjV+RCZvAXVRJfXWiJ8iYEtfHlKgcqqqXg9uUkIolEHuUaMmm8/lcO4xwCOtaw6mY0gStn2Lg4/eUXXYQ== dependencies: - "@typescript-eslint/experimental-utils" "2.16.0" + "@typescript-eslint/experimental-utils" "2.18.0" eslint-utils "^1.4.3" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@2.16.0": - version "2.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.16.0.tgz#bba65685728c532e0ddc811a0376e8d38e671f77" - integrity sha512-bXTmAztXpqxliDKZgvWkl+5dHeRN+jqXVZ16peKKFzSXVzT6mz8kgBpHiVzEKO2NZ8OCU7dG61K9sRS/SkUUFQ== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.16.0" - eslint-scope "^5.0.0" - -"@typescript-eslint/experimental-utils@^2.5.0": - version "2.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.17.0.tgz#12ed4a5d656e02ff47a93efc7d1ce1b8f1242351" - integrity sha512-2bNf+mZ/3mj5/3CP56v+ldRK3vFy9jOvmCPs/Gr2DeSJh+asPZrhFniv4QmQsHWQFPJFWhFHgkGgJeRmK4m8iQ== +"@typescript-eslint/experimental-utils@2.18.0", "@typescript-eslint/experimental-utils@^2.5.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.18.0.tgz#e4eab839082030282496c1439bbf9fdf2a4f3da8" + integrity sha512-J6MopKPHuJYmQUkANLip7g9I82ZLe1naCbxZZW3O2sIxTiq/9YYoOELEKY7oPg0hJ0V/AQ225h2z0Yp+RRMXhw== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.17.0" + "@typescript-eslint/typescript-estree" "2.18.0" eslint-scope "^5.0.0" -"@typescript-eslint/parser@2.16.0": - version "2.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.16.0.tgz#d0c0135a8fdb915f670802ddd7c1ba457c1b4f9d" - integrity sha512-+w8dMaYETM9v6il1yYYkApMSiwgnqXWJbXrA94LAWN603vXHACsZTirJduyeBOJjA9wT6xuXe5zZ1iCUzoxCfw== +"@typescript-eslint/parser@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.18.0.tgz#d5f7fc1839abd4a985394e40e9d2454bd56aeb1f" + integrity sha512-SJJPxFMEYEWkM6pGfcnjLU+NJIPo+Ko1QrCBL+i0+zV30ggLD90huEmMMhKLHBpESWy9lVEeWlQibweNQzyc+A== dependencies: "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.16.0" - "@typescript-eslint/typescript-estree" "2.16.0" + "@typescript-eslint/experimental-utils" "2.18.0" + "@typescript-eslint/typescript-estree" "2.18.0" eslint-visitor-keys "^1.1.0" -"@typescript-eslint/typescript-estree@2.16.0": - version "2.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.16.0.tgz#b444943a76c716ed32abd08cbe96172d2ca0ab75" - integrity sha512-hyrCYjFHISos68Bk5KjUAXw0pP/455qq9nxqB1KkT67Pxjcfw+r6Yhcmqnp8etFL45UexCHUMrADHH7dI/m2WQ== +"@typescript-eslint/typescript-estree@2.18.0": + version "2.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.18.0.tgz#cfbd16ed1b111166617d718619c19b62764c8460" + integrity sha512-gVHylf7FDb8VSi2ypFuEL3hOtoC4HkZZ5dOjXvVjoyKdRrvXAOPSzpNRnKMfaUUEiSLP8UF9j9X9EDLxC0lfZg== dependencies: debug "^4.1.1" eslint-visitor-keys "^1.1.0" @@ -241,18 +232,10 @@ semver "^6.3.0" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@2.17.0": - version "2.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.17.0.tgz#2ce1531ec0925ef8d22d7026235917c2638a82af" - integrity sha512-g0eVRULGnEEUakxRfJO0s0Hr1LLQqsI6OrkiCLpdHtdJJek+wyd8mb00vedqAoWldeDcOcP8plqw8/jx9Gr3Lw== - dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^6.3.0" - tsutils "^3.17.1" +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== accepts@~1.3.7: version "1.3.7" @@ -382,6 +365,19 @@ app-root-path@^2.0.1: resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a" integrity sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA== +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + arg@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.2.tgz#e70c90579e02c63d80e3ad4e31d8bfdb8bd50064" @@ -605,9 +601,9 @@ bootswatch@^4.3.1: integrity sha512-Kx3z6+3Jpg9g6l/xZBCn |