Add default post listing (#645)

* Fix local development.

* Updating translations.

* Adding default site post listing. Fixes #625
This commit is contained in:
Dessalines 2022-05-23 15:19:14 -04:00 committed by GitHub
parent 321339c6c5
commit d4ca2085ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 108 additions and 46 deletions

@ -1 +1 @@
Subproject commit 2e9f6291c91a9c97fa7f7740f90ee3146515e03c Subproject commit 1cbac3a1521e26b9b5c1c97a0c9852655ddcf00b

View file

@ -74,7 +74,7 @@
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.4", "husky": "^7.0.4",
"import-sort-style-module": "^6.0.0", "import-sort-style-module": "^6.0.0",
"lemmy-js-client": "0.16.4-rc.1", "lemmy-js-client": "0.17.0-rc.5",
"lint-staged": "^12.4.1", "lint-staged": "^12.4.1",
"mini-css-extract-plugin": "^2.6.0", "mini-css-extract-plugin": "^2.6.0",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",

View file

@ -27,18 +27,15 @@ const [hostname, port] = process.env["LEMMY_UI_HOST"]
const extraThemesFolder = const extraThemesFolder =
process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes"; process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes";
server.use(function (_req, res, next) { if (process.env.NODE_ENV !== "development") {
// in debug mode, websocket backend may be on another port, so we need to permit it in csp policy server.use(function (_req, res, next) {
var websocketBackend; res.setHeader(
if (process.env.NODE_ENV == "development") { "Content-Security-Policy",
websocketBackend = wsUriBase; `default-src 'none'; connect-src 'self' ${wsUriBase}; img-src * data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; form-action 'self'; base-uri 'self'`
} );
res.setHeader( next();
"Content-Security-Policy", });
`default-src 'none'; connect-src 'self' ${websocketBackend}; img-src * data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; form-action 'self'; base-uri 'self'` }
);
next();
});
server.use(express.json()); server.use(express.json());
server.use(express.urlencoded({ extended: false })); server.use(express.urlencoded({ extended: false }));
server.use("/static", express.static(path.resolve("./dist"))); server.use("/static", express.static(path.resolve("./dist")));

View file

@ -6,7 +6,8 @@ import { randomStr } from "../../utils";
interface ListingTypeSelectProps { interface ListingTypeSelectProps {
type_: ListingType; type_: ListingType;
showLocal?: boolean; showLocal: boolean;
showSubscribed: boolean;
onChange?(val: ListingType): any; onChange?(val: ListingType): any;
} }
@ -33,15 +34,17 @@ export class ListingTypeSelect extends Component<
return { return {
type_: props.type_, type_: props.type_,
showLocal: props.showLocal, showLocal: props.showLocal,
showSubscribed: props.showSubscribed,
}; };
} }
render() { render() {
return ( return (
<div class="btn-group btn-group-toggle flex-wrap mb-2"> <div class="btn-group btn-group-toggle flex-wrap mb-2">
<label {this.props.showSubscribed && (
title={i18n.t("subscribed_description")} <label
className={`btn btn-outline-secondary title={i18n.t("subscribed_description")}
className={`btn btn-outline-secondary
${this.state.type_ == ListingType.Subscribed && "active"} ${this.state.type_ == ListingType.Subscribed && "active"}
${ ${
UserService.Instance.myUserInfo == undefined UserService.Instance.myUserInfo == undefined
@ -49,17 +52,18 @@ export class ListingTypeSelect extends Component<
: "pointer" : "pointer"
} }
`} `}
> >
<input <input
id={`${this.id}-subscribed`} id={`${this.id}-subscribed`}
type="radio" type="radio"
value={ListingType.Subscribed} value={ListingType.Subscribed}
checked={this.state.type_ == ListingType.Subscribed} checked={this.state.type_ == ListingType.Subscribed}
onChange={linkEvent(this, this.handleTypeChange)} onChange={linkEvent(this, this.handleTypeChange)}
disabled={UserService.Instance.myUserInfo == undefined} disabled={UserService.Instance.myUserInfo == undefined}
/> />
{i18n.t("subscribed")} {i18n.t("subscribed")}
</label> </label>
)}
{this.props.showLocal && ( {this.props.showLocal && (
<label <label
title={i18n.t("local_description")} title={i18n.t("local_description")}

View file

@ -128,6 +128,7 @@ export class Communities extends Component<any, CommunitiesState> {
<ListingTypeSelect <ListingTypeSelect
type_={this.state.listingType} type_={this.state.listingType}
showLocal={showLocal(this.isoData)} showLocal={showLocal(this.isoData)}
showSubscribed
onChange={this.handleListingTypeChange} onChange={this.handleListingTypeChange}
/> />
</span> </span>

View file

@ -45,6 +45,7 @@ import {
setIsoData, setIsoData,
setOptionalAuth, setOptionalAuth,
setupTippy, setupTippy,
showLocal,
toast, toast,
updatePersonBlock, updatePersonBlock,
wsClient, wsClient,
@ -280,7 +281,10 @@ export class Community extends Component<any, State> {
} }
/> />
{!cv.community.local && this.state.communityRes.site && ( {!cv.community.local && this.state.communityRes.site && (
<SiteSidebar site={this.state.communityRes.site} /> <SiteSidebar
site={this.state.communityRes.site}
showLocal={showLocal(this.isoData)}
/>
)} )}
</> </>
)} )}
@ -301,7 +305,10 @@ export class Community extends Component<any, State> {
enableNsfw={this.state.siteRes.site_view.site.enable_nsfw} enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
/> />
{!cv.community.local && this.state.communityRes.site && ( {!cv.community.local && this.state.communityRes.site && (
<SiteSidebar site={this.state.communityRes.site} /> <SiteSidebar
site={this.state.communityRes.site}
showLocal={showLocal(this.isoData)}
/>
)} )}
</div> </div>
</div> </div>

View file

@ -21,6 +21,7 @@ import {
isBrowser, isBrowser,
randomStr, randomStr,
setIsoData, setIsoData,
showLocal,
toast, toast,
wsClient, wsClient,
wsJsonToRes, wsJsonToRes,
@ -133,7 +134,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
path={this.context.router.route.match.url} path={this.context.router.route.match.url}
/> />
{this.state.siteRes.site_view.site.id && ( {this.state.siteRes.site_view.site.id && (
<SiteForm site={this.state.siteRes.site_view.site} /> <SiteForm
site={this.state.siteRes.site_view.site}
showLocal={showLocal(this.isoData)}
/>
)} )}
{this.admins()} {this.admins()}
{this.bannedUsers()} {this.bannedUsers()}

View file

@ -110,7 +110,12 @@ export class Home extends Component<any, HomeState> {
loading: true, loading: true,
posts: [], posts: [],
comments: [], comments: [],
listingType: getListingTypeFromProps(this.props), listingType: getListingTypeFromProps(
this.props,
ListingType[
this.isoData.site_res.site_view.site.default_post_listing_type
]
),
dataType: getDataTypeFromProps(this.props), dataType: getDataTypeFromProps(this.props),
sort: getSortTypeFromProps(this.props), sort: getSortTypeFromProps(this.props),
page: getPageFromProps(this.props), page: getPageFromProps(this.props),
@ -173,7 +178,7 @@ export class Home extends Component<any, HomeState> {
static getDerivedStateFromProps(props: any): HomeProps { static getDerivedStateFromProps(props: any): HomeProps {
return { return {
listingType: getListingTypeFromProps(props), listingType: getListingTypeFromProps(props, ListingType.Local),
dataType: getDataTypeFromProps(props), dataType: getDataTypeFromProps(props),
sort: getSortTypeFromProps(props), sort: getSortTypeFromProps(props),
page: getPageFromProps(props), page: getPageFromProps(props),
@ -194,7 +199,7 @@ export class Home extends Component<any, HomeState> {
UserService.Instance.myUserInfo.local_user_view.local_user UserService.Instance.myUserInfo.local_user_view.local_user
.default_listing_type .default_listing_type
] ]
: ListingType.Local; : null;
let sort: SortType = pathSplit[7] let sort: SortType = pathSplit[7]
? SortType[pathSplit[7]] ? SortType[pathSplit[7]]
: UserService.Instance.myUserInfo : UserService.Instance.myUserInfo
@ -213,9 +218,12 @@ export class Home extends Component<any, HomeState> {
page, page,
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_,
saved_only: false, saved_only: false,
}; };
if (type_) {
getPostsForm.type_ = type_;
}
setOptionalAuth(getPostsForm, req.auth); setOptionalAuth(getPostsForm, req.auth);
promises.push(req.client.getPosts(getPostsForm)); promises.push(req.client.getPosts(getPostsForm));
} else { } else {
@ -223,7 +231,7 @@ export class Home extends Component<any, HomeState> {
page, page,
limit: fetchLimit, limit: fetchLimit,
sort, sort,
type_, type_: type_ || ListingType.Local,
saved_only: false, saved_only: false,
}; };
setOptionalAuth(getCommentsForm, req.auth); setOptionalAuth(getCommentsForm, req.auth);
@ -335,6 +343,7 @@ export class Home extends Component<any, HomeState> {
admins={siteRes.admins} admins={siteRes.admins}
counts={siteRes.site_view.counts} counts={siteRes.site_view.counts}
online={siteRes.online} online={siteRes.online}
showLocal={showLocal(this.isoData)}
/> />
)} )}
{this.state.showTrendingMobile && ( {this.state.showTrendingMobile && (
@ -371,6 +380,7 @@ export class Home extends Component<any, HomeState> {
admins={siteRes.admins} admins={siteRes.admins}
counts={siteRes.site_view.counts} counts={siteRes.site_view.counts}
online={siteRes.online} online={siteRes.online}
showLocal={showLocal(this.isoData)}
/> />
{UserService.Instance.myUserInfo && {UserService.Instance.myUserInfo &&
@ -530,6 +540,7 @@ export class Home extends Component<any, HomeState> {
<ListingTypeSelect <ListingTypeSelect
type_={this.state.listingType} type_={this.state.listingType}
showLocal={showLocal(this.isoData)} showLocal={showLocal(this.isoData)}
showSubscribed
onChange={this.handleListingTypeChange} onChange={this.handleListingTypeChange}
/> />
</span> </span>
@ -615,10 +626,13 @@ export class Home extends Component<any, HomeState> {
page: this.state.page, page: this.state.page,
limit: fetchLimit, limit: fetchLimit,
sort: this.state.sort, sort: this.state.sort,
type_: this.state.listingType,
saved_only: false, saved_only: false,
auth: authField(false), auth: authField(false),
}; };
if (this.state.listingType) {
getPostsForm.type_ = this.state.listingType;
}
WebSocketService.Instance.send(wsClient.getPosts(getPostsForm)); WebSocketService.Instance.send(wsClient.getPosts(getPostsForm));
} else { } else {
let getCommentsForm: GetComments = { let getCommentsForm: GetComments = {

View file

@ -64,7 +64,7 @@ export class Setup extends Component<any, State> {
{!this.state.doneRegisteringUser ? ( {!this.state.doneRegisteringUser ? (
this.registerUser() this.registerUser()
) : ( ) : (
<SiteForm /> <SiteForm showLocal />
)} )}
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
import { Component, linkEvent } from "inferno"; import { Component, linkEvent } from "inferno";
import { Prompt } from "inferno-router"; import { Prompt } from "inferno-router";
import { CreateSite, EditSite, Site } from "lemmy-js-client"; import { CreateSite, EditSite, ListingType, Site } from "lemmy-js-client";
import { i18n } from "../../i18next"; import { i18n } from "../../i18next";
import { WebSocketService } from "../../services"; import { WebSocketService } from "../../services";
import { import {
@ -11,10 +11,12 @@ import {
} from "../../utils"; } from "../../utils";
import { Spinner } from "../common/icon"; import { Spinner } from "../common/icon";
import { ImageUploadForm } from "../common/image-upload-form"; import { ImageUploadForm } from "../common/image-upload-form";
import { ListingTypeSelect } from "../common/listing-type-select";
import { MarkdownTextArea } from "../common/markdown-textarea"; import { MarkdownTextArea } from "../common/markdown-textarea";
interface SiteFormProps { interface SiteFormProps {
site?: Site; // If a site is given, that means this is an edit site?: Site; // If a site is given, that means this is an edit
showLocal: boolean;
onCancel?(): any; onCancel?(): any;
onEdit?(): any; onEdit?(): any;
} }
@ -39,6 +41,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
application_question: null, application_question: null,
private_instance: null, private_instance: null,
default_theme: null, default_theme: null,
default_post_listing_type: null,
auth: authField(false), auth: authField(false),
}, },
loading: false, loading: false,
@ -59,6 +62,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
this.handleBannerUpload = this.handleBannerUpload.bind(this); this.handleBannerUpload = this.handleBannerUpload.bind(this);
this.handleBannerRemove = this.handleBannerRemove.bind(this); this.handleBannerRemove = this.handleBannerRemove.bind(this);
this.handleDefaultPostListingTypeChange =
this.handleDefaultPostListingTypeChange.bind(this);
if (this.props.site) { if (this.props.site) {
let site = this.props.site; let site = this.props.site;
this.state.siteForm = { this.state.siteForm = {
@ -76,6 +82,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
application_question: site.application_question, application_question: site.application_question,
private_instance: site.private_instance, private_instance: site.private_instance,
default_theme: site.default_theme, default_theme: site.default_theme,
default_post_listing_type: site.default_post_listing_type,
auth: authField(false), auth: authField(false),
}; };
} }
@ -350,6 +357,21 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
</select> </select>
</div> </div>
</div> </div>
{this.props.showLocal && (
<form className="form-group row">
<label class="col-sm-3">{i18n.t("listing_type")}</label>
<div class="col-sm-9">
<ListingTypeSelect
type_={
ListingType[this.state.siteForm.default_post_listing_type]
}
showLocal
showSubscribed={false}
onChange={this.handleDefaultPostListingTypeChange}
/>
</div>
</form>
)}
<div class="form-group row"> <div class="form-group row">
<div class="col-12"> <div class="col-12">
<div class="form-check"> <div class="form-check">
@ -499,4 +521,10 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
this.state.siteForm.banner = ""; this.state.siteForm.banner = "";
this.setState(this.state); this.setState(this.state);
} }
handleDefaultPostListingTypeChange(val: ListingType) {
this.state.siteForm.default_post_listing_type =
ListingType[ListingType[val]];
this.setState(this.state);
}
} }

View file

@ -11,6 +11,7 @@ import { SiteForm } from "./site-form";
interface SiteSidebarProps { interface SiteSidebarProps {
site: Site; site: Site;
showLocal: boolean;
counts?: SiteAggregates; counts?: SiteAggregates;
admins?: PersonViewSafe[]; admins?: PersonViewSafe[];
online?: number; online?: number;
@ -55,6 +56,7 @@ export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
) : ( ) : (
<SiteForm <SiteForm
site={site} site={site}
showLocal={this.props.showLocal}
onEdit={this.handleEditSite} onEdit={this.handleEditSite}
onCancel={this.handleEditCancel} onCancel={this.handleEditCancel}
/> />

View file

@ -565,6 +565,7 @@ export class Settings extends Component<any, SettingsState> {
] ]
} }
showLocal={showLocal(this.isoData)} showLocal={showLocal(this.isoData)}
showSubscribed
onChange={this.handleListingTypeChange} onChange={this.handleListingTypeChange}
/> />
</div> </div>

View file

@ -403,6 +403,7 @@ export class Search extends Component<any, SearchState> {
<ListingTypeSelect <ListingTypeSelect
type_={this.state.listingType} type_={this.state.listingType}
showLocal={showLocal(this.isoData)} showLocal={showLocal(this.isoData)}
showSubscribed
onChange={this.handleListingTypeChange} onChange={this.handleListingTypeChange}
/> />
</span> </span>

View file

@ -664,7 +664,10 @@ async function communitySearch(text: string): Promise<CommunityTribute[]> {
return communities; return communities;
} }
export function getListingTypeFromProps(props: any): ListingType { export function getListingTypeFromProps(
props: any,
defaultListingType: ListingType
): ListingType {
return props.match.params.listing_type return props.match.params.listing_type
? routeListingTypeToEnum(props.match.params.listing_type) ? routeListingTypeToEnum(props.match.params.listing_type)
: UserService.Instance.myUserInfo : UserService.Instance.myUserInfo
@ -672,7 +675,7 @@ export function getListingTypeFromProps(props: any): ListingType {
UserService.Instance.myUserInfo.local_user_view.local_user UserService.Instance.myUserInfo.local_user_view.local_user
.default_listing_type .default_listing_type
] ]
: ListingType.Local; : defaultListingType;
} }
export function getListingTypeFromPropsNoDefault(props: any): ListingType { export function getListingTypeFromPropsNoDefault(props: any): ListingType {

View file

@ -4813,10 +4813,10 @@ lcid@^1.0.0:
dependencies: dependencies:
invert-kv "^1.0.0" invert-kv "^1.0.0"
lemmy-js-client@0.16.4-rc.1: lemmy-js-client@0.17.0-rc.5:
version "0.16.4-rc.1" version "0.17.0-rc.5"
resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.16.4-rc.1.tgz#dfa94a152a7abe75f50f2599a8d9b40c143f37ff" resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.5.tgz#8065ddca68acfbccc7a693ae0f31d6ab66dce972"
integrity sha512-94Xh7A/WDywRaJ0GPXPaXZhyXqMzK0gAISNSB8m++2mC1WJalOqfjR72q/7PmLGxfjYO88/aWSz4Sk0SXWJjCw== integrity sha512-IuSYaK4//KVFg+s4Av/PaxMM2tQpP3sL6G3zXfzbrZfCEtBp9ZlOEMFAu/neRgNumVh+R/koIwf8iLh4UdYCdg==
levn@^0.4.1: levn@^0.4.1:
version "0.4.1" version "0.4.1"