Modlog, admin-settings, search, and user done.

This commit is contained in:
Dessalines 2020-09-08 21:40:36 -05:00
parent 95b74ad74c
commit bea7a37983
6 changed files with 170 additions and 133 deletions

View file

@ -1,7 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet'; import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import { import {
UserOperation, UserOperation,
SiteResponse, SiteResponse,
@ -9,9 +8,20 @@ import {
SiteConfigForm, SiteConfigForm,
GetSiteConfigResponse, GetSiteConfigResponse,
WebSocketJsonResponse, WebSocketJsonResponse,
GetSiteConfig,
} from 'lemmy-js-client'; } from 'lemmy-js-client';
import { WebSocketService } from '../services'; import { WebSocketService } from '../services';
import { wsJsonToRes, capitalizeFirstLetter, toast, randomStr } from '../utils'; import {
wsJsonToRes,
capitalizeFirstLetter,
toast,
randomStr,
setIsoData,
wsSubscribe,
isBrowser,
lemmyHttp,
setAuth,
} from '../utils';
import autosize from 'autosize'; import autosize from 'autosize';
import { SiteForm } from './site-form'; import { SiteForm } from './site-form';
import { UserListing } from './user-listing'; import { UserListing } from './user-listing';
@ -27,29 +37,10 @@ interface AdminSettingsState {
export class AdminSettings extends Component<any, AdminSettingsState> { export class AdminSettings extends Component<any, AdminSettingsState> {
private siteConfigTextAreaId = `site-config-${randomStr()}`; private siteConfigTextAreaId = `site-config-${randomStr()}`;
private isoData = setIsoData(this.context);
private subscription: Subscription; private subscription: Subscription;
private emptyState: AdminSettingsState = { private emptyState: AdminSettingsState = {
siteRes: { siteRes: this.isoData.site,
site: {
id: null,
name: null,
creator_id: null,
creator_name: null,
published: null,
number_of_users: null,
number_of_posts: null,
number_of_comments: null,
number_of_communities: null,
enable_downvotes: null,
open_registration: null,
enable_nsfw: null,
},
admins: [],
banned: [],
online: null,
version: null,
federated_instances: null,
},
siteConfigForm: { siteConfigForm: {
config_hjson: null, config_hjson: null,
auth: null, auth: null,
@ -66,28 +57,41 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
this.state = this.emptyState; this.state = this.emptyState;
this.subscription = WebSocketService.Instance.subject this.parseMessage = this.parseMessage.bind(this);
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) this.subscription = wsSubscribe(this.parseMessage);
.subscribe(
msg => this.parseMessage(msg),
err => console.error(err),
() => console.log('complete')
);
WebSocketService.Instance.getSite(); // Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
this.state.siteConfigRes = this.isoData.routeData[0];
this.state.siteConfigForm.config_hjson = this.state.siteConfigRes.config_hjson;
this.state.siteConfigLoading = false;
this.state.loading = false;
} else {
WebSocketService.Instance.getSiteConfig(); WebSocketService.Instance.getSiteConfig();
} }
}
static fetchInitialData(auth: string, _path: string): Promise<any>[] {
let form: GetSiteConfig = {};
setAuth(form, auth);
return [lemmyHttp.getSiteConfig(form)];
}
componentDidMount() {
if (isBrowser()) {
var textarea: any = document.getElementById(this.siteConfigTextAreaId);
autosize(textarea);
}
}
componentWillUnmount() { componentWillUnmount() {
if (isBrowser()) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }
}
get documentTitle(): string { get documentTitle(): string {
if (this.state.siteRes.site.name) {
return `${i18n.t('admin_settings')} - ${this.state.siteRes.site.name}`; return `${i18n.t('admin_settings')} - ${this.state.siteRes.site.name}`;
} else {
return 'Lemmy';
}
} }
render() { render() {
@ -226,15 +230,6 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
this.setState(this.state); this.setState(this.state);
return; return;
} else if (msg.reconnect) { } else if (msg.reconnect) {
} else if (res.op == UserOperation.GetSite) {
let data = res.data as GetSiteResponse;
// This means it hasn't been set up yet
if (!data.site) {
this.context.router.history.push('/setup');
}
this.state.siteRes = data;
this.setState(this.state);
} else if (res.op == UserOperation.EditSite) { } else if (res.op == UserOperation.EditSite) {
let data = res.data as SiteResponse; let data = res.data as SiteResponse;
this.state.siteRes.site = data.site; this.state.siteRes.site = data.site;

View file

@ -2,7 +2,6 @@ import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet'; import { Helmet } from 'inferno-helmet';
import { Link } from 'inferno-router'; import { Link } from 'inferno-router';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import { import {
UserOperation, UserOperation,
GetModlogForm, GetModlogForm,
@ -17,11 +16,19 @@ import {
ModAddCommunity, ModAddCommunity,
ModAdd, ModAdd,
WebSocketJsonResponse, WebSocketJsonResponse,
GetSiteResponse,
Site, Site,
} from 'lemmy-js-client'; } from 'lemmy-js-client';
import { WebSocketService } from '../services'; import { WebSocketService } from '../services';
import { wsJsonToRes, addTypeInfo, fetchLimit, toast } from '../utils'; import {
wsJsonToRes,
addTypeInfo,
fetchLimit,
toast,
setIsoData,
wsSubscribe,
isBrowser,
lemmyHttp,
} from '../utils';
import { MomentTime } from './moment-time'; import { MomentTime } from './moment-time';
import moment from 'moment'; import moment from 'moment';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
@ -45,12 +52,13 @@ interface ModlogState {
} }
export class Modlog extends Component<any, ModlogState> { export class Modlog extends Component<any, ModlogState> {
private isoData = setIsoData(this.context);
private subscription: Subscription; private subscription: Subscription;
private emptyState: ModlogState = { private emptyState: ModlogState = {
combined: [], combined: [],
page: 1, page: 1,
loading: true, loading: true,
site: undefined, site: this.isoData.site.site,
}; };
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -60,21 +68,25 @@ export class Modlog extends Component<any, ModlogState> {
this.state.communityId = this.props.match.params.community_id this.state.communityId = this.props.match.params.community_id
? Number(this.props.match.params.community_id) ? Number(this.props.match.params.community_id)
: undefined; : undefined;
this.subscription = WebSocketService.Instance.subject
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
.subscribe(
msg => this.parseMessage(msg),
err => console.error(err),
() => console.log('complete')
);
this.parseMessage = this.parseMessage.bind(this);
this.subscription = wsSubscribe(this.parseMessage);
// Only fetch the data if coming from another route
if (this.isoData.path == this.context.router.route.match.url) {
let data = this.isoData.routeData[0];
this.setCombined(data);
this.state.loading = false;
} else {
this.refetch(); this.refetch();
WebSocketService.Instance.getSite(); }
} }
componentWillUnmount() { componentWillUnmount() {
if (isBrowser()) {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
} }
}
setCombined(res: GetModlogResponse) { setCombined(res: GetModlogResponse) {
let removed_posts = addTypeInfo(res.removed_posts, 'removed_posts'); let removed_posts = addTypeInfo(res.removed_posts, 'removed_posts');
@ -119,8 +131,6 @@ export class Modlog extends Component<any, ModlogState> {
this.state.combined.sort((a, b) => this.state.combined.sort((a, b) =>
b.data.when_.localeCompare(a.data.when_) b.data.when_.localeCompare(a.data.when_)
); );
this.setState(this.state);
} }
combined() { combined() {
@ -434,6 +444,24 @@ export class Modlog extends Component<any, ModlogState> {
WebSocketService.Instance.getModlog(modlogForm); WebSocketService.Instance.getModlog(modlogForm);
} }
static fetchInitialData(_auth: string, path: string): Promise<any>[] {
let pathSplit = path.split('/');
let communityId = pathSplit[3];
let promises: Promise<any>[] = [];
let modlogForm: GetModlogForm = {
page: 1,
limit: fetchLimit,
};
if (communityId) {
modlogForm.community_id = Number(communityId);
}
promises.push(lemmyHttp.getModlog(modlogForm));
return promises;
}
parseMessage(msg: WebSocketJsonResponse) { parseMessage(msg: WebSocketJsonResponse) {
console.log(msg); console.log(msg);
let res = wsJsonToRes(msg); let res = wsJsonToRes(msg);
@ -445,9 +473,6 @@ export class Modlog extends Component<any, ModlogState> {
this.state.loading = false; this.state.loading = false;
window.scrollTo(0, 0); window.scrollTo(0, 0);
this.setCombined(data); this.setCombined(data);
} else if (res.op == UserOperation.GetSite) {
let data = res.data as GetSiteResponse;
this.state.site = data.site;
this.setState(this.state); this.setState(this.state);
} }
} }

View file

@ -1,7 +1,6 @@
import { Component, linkEvent } from 'inferno'; import { Component, linkEvent } from 'inferno';
import { Helmet } from 'inferno-helmet'; import { Helmet } from 'inferno-helmet';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { retryWhen, delay, take } from 'rxjs/operators';
import { import {
UserOperation, UserOperation,
Post, Post,
@ -15,7 +14,6 @@ import {
PostResponse, PostResponse,
CommentResponse, CommentResponse,
WebSocketJsonResponse, WebSocketJsonResponse,
GetSiteResponse,
Site, Site,
} from 'lemmy-js-client'; } from 'lemmy-js-client';
import { WebSocketService } from '../services'; import { WebSocketService } from '../services';
@ -28,7 +26,10 @@ import {
createCommentLikeRes, createCommentLikeRes,
createPostLikeFindRes, createPostLikeFindRes,
commentsToFlatNodes, commentsToFlatNodes,
getPageFromProps, setIsoData,
wsSubscribe,
lemmyHttp,
setAuth,
} from '../utils'; } from '../utils';
import { PostListing } from './post-listing'; import { PostListing } from './post-listing';
import { UserListing } from './user-listing'; import { UserListing } from './user-listing';
@ -37,6 +38,13 @@ import { SortSelect } from './sort-select';
import { CommentNodes } from './comment-nodes'; import { CommentNodes } from './comment-nodes';
import { i18n } from '../i18next'; import { i18n } from '../i18next';
interface SearchProps {
q: string;
type_: SearchType;
sort: SortType;
page: number;
}
interface SearchState { interface SearchState {
q: string; q: string;
type_: SearchType; type_: SearchType;
@ -48,13 +56,6 @@ interface SearchState {
searchText: string; searchText: string;
} }
interface SearchProps {
q: string;
type_: SearchType;
sort: SortType;
page: number;
}
interface UrlParams { interface UrlParams {
q?: string; q?: string;
type_?: SearchType; type_?: SearchType;
@ -63,13 +64,14 @@ interface UrlParams {
} }
export class Search extends Component<any, SearchState> { export class Search extends Component<any, SearchState> {
private isoData = setIsoData(this.context);
private subscription: Subscription; private subscription: Subscription;
private emptyState: SearchState = { private emptyState: SearchState = {
q: Search.getSearchQueryFromProps(this.props), q: Search.getSearchQueryFromProps(this.props.match.params.q),
type_: Search.getSearchTypeFromProps(this.props), type_: Search.getSearchTypeFromProps(this.props.match.params.type),
sort: Search.getSortTypeFromProps(this.props), sort: Search.getSortTypeFromProps(this.props.match.params.sort),
page: getPageFromProps(this.props), page: Search.getPageFromProps(this.props.match.params.page),
searchText: Search.getSearchQueryFromProps(this.props), searchText: Search.getSearchQueryFromProps(this.props.match.params.q),
searchResponse: { searchResponse: {
type_: null, type_: null,
posts: [], posts: [],
@ -78,36 +80,23 @@ export class Search extends Component<any, SearchState> {
users: [], users: [],
}, },
loading: false, loading: false,
site: { site: this.isoData.site.site,
id: undefined,
name: undefined,
creator_id: undefined,
published: undefined,
creator_name: undefined,
number_of_users: undefined,
number_of_posts: undefined,
number_of_comments: undefined,
number_of_communities: undefined,
enable_downvotes: undefined,
open_registration: undefined,
enable_nsfw: undefined,
},
}; };
static getSearchQueryFromProps(props: any): string { static getSearchQueryFromProps(q: string): string {
return props.match.params.q ? props.match.params.q : ''; return q || '';
} }
static getSearchTypeFromProps(props: any): SearchType { static getSearchTypeFromProps(type_: string): SearchType {
return props.match.params.type return type_ ? routeSearchTypeToEnum(type_) : SearchType.All;
? routeSearchTypeToEnum(props.match.params.type)
: SearchType.All;
} }
static getSortTypeFromProps(props: any): SortType { static getSortTypeFromProps(sort: string): SortType {
return props.match.params.sort return sort ? routeSortTypeToEnum(sort) : SortType.TopAll;
? routeSortTypeToEnum(props.match.params.sort) }
: SortType.TopAll;
static getPageFromProps(page: string): number {
return page ? Number(page) : 1;
} }
constructor(props: any, context: any) { constructor(props: any, context: any) {
@ -116,20 +105,19 @@ export class Search extends Component<any, SearchState> {
this.state = this.emptyState; this.state = this.emptyState;
this.handleSortChange = this.handleSortChange.bind(this); this.handleSortChange = this.handleSortChange.bind(this);
this.subscription = WebSocketService.Instance.subject this.parseMessage = this.parseMessage.bind(this);
.pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) this.subscription = wsSubscribe(this.parseMessage);
.subscribe(
msg => this.parseMessage(msg),
err => console.error(err),
() => console.log('complete')
);
WebSocketService.Instance.getSite(); // Only fetch the data if coming from another route
if (this.state.q != '') {
if (this.state.q) { if (this.isoData.path == this.context.router.route.match.url) {
this.state.searchResponse = this.isoData.routeData[0];
this.state.loading = false;
} else {
this.search(); this.search();
} }
} }
}
componentWillUnmount() { componentWillUnmount() {
this.subscription.unsubscribe(); this.subscription.unsubscribe();
@ -137,13 +125,33 @@ export class Search extends Component<any, SearchState> {
static getDerivedStateFromProps(props: any): SearchProps { static getDerivedStateFromProps(props: any): SearchProps {
return { return {
q: Search.getSearchQueryFromProps(props), q: Search.getSearchQueryFromProps(props.match.params.q),
type_: Search.getSearchTypeFromProps(props), type_: Search.getSearchTypeFromProps(props.match.params.type),
sort: Search.getSortTypeFromProps(props), sort: Search.getSortTypeFromProps(props.match.params.sort),
page: getPageFromProps(props), page: Search.getPageFromProps(props.match.params.page),
}; };
} }
static fetchInitialData(auth: string, path: string): Promise<any>[] {
let pathSplit = path.split('/');
let promises: Promise<any>[] = [];
let form: SearchForm = {
q: this.getSearchQueryFromProps(pathSplit[3]),
type_: this.getSearchTypeFromProps(pathSplit[5]),
sort: this.getSortTypeFromProps(pathSplit[7]),
page: this.getPageFromProps(pathSplit[9]),
limit: fetchLimit,
};
setAuth(form, auth);
if (form.q != '') {
promises.push(lemmyHttp.search(form));
}
return promises;
}
componentDidUpdate(_: any, lastState: SearchState) { componentDidUpdate(_: any, lastState: SearchState) {
if ( if (
lastState.q !== this.state.q || lastState.q !== this.state.q ||
@ -289,6 +297,7 @@ export class Search extends Component<any, SearchState> {
<div class="col-12"> <div class="col-12">
{i.type_ == 'posts' && ( {i.type_ == 'posts' && (
<PostListing <PostListing
communities={[]}
key={(i.data as Post).id} key={(i.data as Post).id}
post={i.data as Post} post={i.data as Post}
showCommunity showCommunity
@ -351,6 +360,7 @@ export class Search extends Component<any, SearchState> {
<div class="row"> <div class="row">
<div class="col-12"> <div class="col-12">
<PostListing <PostListing
communities={[]}
post={post} post={post}
showCommunity showCommunity
enableDownvotes={this.state.site.enable_downvotes} enableDownvotes={this.state.site.enable_downvotes}
@ -527,10 +537,6 @@ export class Search extends Component<any, SearchState> {
let data = res.data as PostResponse; let data = res.data as PostResponse;
createPostLikeFindRes(data, this.state.searchResponse.posts); createPostLikeFindRes(data, this.state.searchResponse.posts);
this.setState(this.state); this.setState(this.state);
} else if (res.op == UserOperation.GetSite) {
let data = res.data as GetSiteResponse;
this.state.site = data.site;
this.setState(this.state);
} }
} }
} }

View file

@ -68,11 +68,7 @@ export class Sponsors extends Component<any, SponsorsState> {
} }
get documentTitle(): string { get documentTitle(): string {
if (this.state.site) {
return `${i18n.t('sponsors')} - ${this.state.site.name}`; return `${i18n.t('sponsors')} - ${this.state.site.name}`;
} else {
return 'Lemmy';
}
} }
render() { render() {

View file

@ -109,15 +109,30 @@ export const routes: IRoutePropsWithFetch[] = [
{ {
path: `/modlog/community/:community_id`, path: `/modlog/community/:community_id`,
component: Modlog, component: Modlog,
fetchInitialData: (auth, path) => Modlog.fetchInitialData(auth, path),
},
{
path: `/modlog`,
component: Modlog,
fetchInitialData: (auth, path) => Modlog.fetchInitialData(auth, path),
}, },
{ path: `/modlog`, component: Modlog },
{ path: `/setup`, component: Setup }, { path: `/setup`, component: Setup },
{ path: `/admin`, component: AdminSettings }, {
path: `/admin`,
component: AdminSettings,
fetchInitialData: (auth, path) =>
AdminSettings.fetchInitialData(auth, path),
},
{ {
path: `/search/q/:q/type/:type/sort/:sort/page/:page`, path: `/search/q/:q/type/:type/sort/:sort/page/:page`,
component: Search, component: Search,
fetchInitialData: (auth, path) => Search.fetchInitialData(auth, path),
},
{
path: `/search`,
component: Search,
fetchInitialData: (auth, path) => Search.fetchInitialData(auth, path),
}, },
{ path: `/search`, component: Search },
{ path: `/sponsors`, component: Sponsors }, { path: `/sponsors`, component: Sponsors },
{ {
path: `/password_change/:token`, path: `/password_change/:token`,

View file

@ -301,7 +301,7 @@ export function routeDataTypeToEnum(type: string): DataType {
} }
export function routeSearchTypeToEnum(type: string): SearchType { export function routeSearchTypeToEnum(type: string): SearchType {
return SearchType[capitalizeFirstLetter(type)]; return SearchType[type];
} }
export async function getPageTitle(url: string) { export async function getPageTitle(url: string) {