mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-22 12:21:13 +00:00
Make admin UI for allowing/blocking instances easier to work with (#1012)
* Make admin UI for allowing/blocking instances easier to work with * Tweak styles * Remove log statements * Trim instance names and slight refactor * Use linkEvent
This commit is contained in:
parent
9d8c7dfb0c
commit
0d30f4c731
3 changed files with 141 additions and 60 deletions
|
@ -106,6 +106,9 @@
|
||||||
<symbol id="icon-refresh-cw" viewBox="0 0 24 24">
|
<symbol id="icon-refresh-cw" viewBox="0 0 24 24">
|
||||||
<path d="M4.453 9.334c0.737-2.083 2.247-3.669 4.096-4.552s4.032-1.059 6.114-0.322c1.186 0.42 2.206 1.088 2.983 1.88l2.83 2.66h-3.476c-0.552 0-1 0.448-1 1s0.448 1 1 1h5.997c0.005 0 0.009 0 0.014 0 0.137-0.001 0.268-0.031 0.386-0.082 0.119-0.051 0.229-0.126 0.324-0.225 0.012-0.013 0.024-0.026 0.036-0.039 0.075-0.087 0.133-0.183 0.173-0.285s0.064-0.211 0.069-0.326c0.001-0.015 0.001-0.029 0.001-0.043v-6c0-0.552-0.448-1-1-1s-1 0.448-1 1v3.689l-2.926-2.749c-0.992-1.010-2.271-1.843-3.743-2.364-2.603-0.921-5.335-0.699-7.643 0.402s-4.199 3.086-5.12 5.689c-0.185 0.52 0.088 1.091 0.608 1.276s1.092-0.088 1.276-0.609zM2 16.312l2.955 2.777c1.929 1.931 4.49 2.908 7.048 2.909s5.119-0.975 7.072-2.927c1.104-1.104 1.901-2.407 2.361-3.745 0.18-0.522-0.098-1.091-0.621-1.271s-1.091 0.098-1.271 0.621c-0.361 1.050-0.993 2.091-1.883 2.981-1.563 1.562-3.609 2.342-5.657 2.342s-4.094-0.782-5.679-2.366l-2.8-2.633h3.475c0.552 0 1-0.448 1-1s-0.448-1-1-1h-5.997c-0.005 0-0.009 0-0.014 0-0.137 0.001-0.268 0.031-0.386 0.082-0.119 0.051-0.229 0.126-0.324 0.225-0.012 0.013-0.024 0.026-0.036 0.039-0.075 0.087-0.133 0.183-0.173 0.285s-0.064 0.211-0.069 0.326c-0.001 0.015-0.001 0.029-0.001 0.043v6c0 0.552 0.448 1 1 1s1-0.448 1-1z"></path>
|
<path d="M4.453 9.334c0.737-2.083 2.247-3.669 4.096-4.552s4.032-1.059 6.114-0.322c1.186 0.42 2.206 1.088 2.983 1.88l2.83 2.66h-3.476c-0.552 0-1 0.448-1 1s0.448 1 1 1h5.997c0.005 0 0.009 0 0.014 0 0.137-0.001 0.268-0.031 0.386-0.082 0.119-0.051 0.229-0.126 0.324-0.225 0.012-0.013 0.024-0.026 0.036-0.039 0.075-0.087 0.133-0.183 0.173-0.285s0.064-0.211 0.069-0.326c0.001-0.015 0.001-0.029 0.001-0.043v-6c0-0.552-0.448-1-1-1s-1 0.448-1 1v3.689l-2.926-2.749c-0.992-1.010-2.271-1.843-3.743-2.364-2.603-0.921-5.335-0.699-7.643 0.402s-4.199 3.086-5.12 5.689c-0.185 0.52 0.088 1.091 0.608 1.276s1.092-0.088 1.276-0.609zM2 16.312l2.955 2.777c1.929 1.931 4.49 2.908 7.048 2.909s5.119-0.975 7.072-2.927c1.104-1.104 1.901-2.407 2.361-3.745 0.18-0.522-0.098-1.091-0.621-1.271s-1.091 0.098-1.271 0.621c-0.361 1.050-0.993 2.091-1.883 2.981-1.563 1.562-3.609 2.342-5.657 2.342s-4.094-0.782-5.679-2.366l-2.8-2.633h3.475c0.552 0 1-0.448 1-1s-0.448-1-1-1h-5.997c-0.005 0-0.009 0-0.014 0-0.137 0.001-0.268 0.031-0.386 0.082-0.119 0.051-0.229 0.126-0.324 0.225-0.012 0.013-0.024 0.026-0.036 0.039-0.075 0.087-0.133 0.183-0.173 0.285s-0.064 0.211-0.069 0.326c-0.001 0.015-0.001 0.029-0.001 0.043v6c0 0.552 0.448 1 1 1s1-0.448 1-1z"></path>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
<symbol id="icon-add" viewBox="0 0 32 32" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<path d="M14.5,14.501l-10.502,0c-0.828,0 -1.5,0.673 -1.5,1.5c0,0.828 0.672,1.5 1.5,1.5l10.502,0l-0.001,10.502c0,0.828 0.672,1.5 1.5,1.501c0.828,-0 1.5,-0.673 1.5,-1.5l0.001,-10.503l10.502,0c0.828,0 1.5,-0.672 1.5,-1.5c0,-0.827 -0.672,-1.5 -1.5,-1.5l-10.502,0l0.001,-10.501c-0,-0.828 -0.672,-1.501 -1.5,-1.501c-0.828,0 -1.5,0.672 -1.5,1.5l-0.001,10.502Z"/>
|
||||||
|
</symbol>
|
||||||
<symbol id="icon-play" viewBox="0 0 24 24">
|
<symbol id="icon-play" viewBox="0 0 24 24">
|
||||||
<path d="M5.541 2.159c-0.153-0.1-0.34-0.159-0.541-0.159-0.552 0-1 0.448-1 1v18c-0.001 0.182 0.050 0.372 0.159 0.541 0.299 0.465 0.917 0.599 1.382 0.3l14-9c0.114-0.072 0.219-0.174 0.3-0.3 0.299-0.465 0.164-1.083-0.3-1.382zM6 4.832l11.151 7.168-11.151 7.168z"></path>
|
<path d="M5.541 2.159c-0.153-0.1-0.34-0.159-0.541-0.159-0.552 0-1 0.448-1 1v18c-0.001 0.182 0.050 0.372 0.159 0.541 0.299 0.465 0.917 0.599 1.382 0.3l14-9c0.114-0.072 0.219-0.174 0.3-0.3 0.299-0.465 0.164-1.083-0.3-1.382zM6 4.832l11.151 7.168-11.151 7.168z"></path>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 53 KiB |
|
@ -1,4 +1,9 @@
|
||||||
import { Component, InfernoMouseEvent, linkEvent } from "inferno";
|
import {
|
||||||
|
Component,
|
||||||
|
InfernoKeyboardEvent,
|
||||||
|
InfernoMouseEvent,
|
||||||
|
linkEvent,
|
||||||
|
} from "inferno";
|
||||||
import { Prompt } from "inferno-router";
|
import { Prompt } from "inferno-router";
|
||||||
import {
|
import {
|
||||||
CreateSite,
|
CreateSite,
|
||||||
|
@ -15,7 +20,7 @@ import {
|
||||||
myAuth,
|
myAuth,
|
||||||
wsClient,
|
wsClient,
|
||||||
} from "../../utils";
|
} from "../../utils";
|
||||||
import { Spinner } from "../common/icon";
|
import { Icon, Spinner } from "../common/icon";
|
||||||
import { ImageUploadForm } from "../common/image-upload-form";
|
import { ImageUploadForm } from "../common/image-upload-form";
|
||||||
import { LanguageSelect } from "../common/language-select";
|
import { LanguageSelect } from "../common/language-select";
|
||||||
import { ListingTypeSelect } from "../common/listing-type-select";
|
import { ListingTypeSelect } from "../common/listing-type-select";
|
||||||
|
@ -31,14 +36,24 @@ interface SiteFormState {
|
||||||
siteForm: EditSite;
|
siteForm: EditSite;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
themeList?: string[];
|
themeList?: string[];
|
||||||
|
instance_select: {
|
||||||
|
allowed_instances: string;
|
||||||
|
blocked_instances: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InstanceKey = "allowed_instances" | "blocked_instances";
|
||||||
|
|
||||||
export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
state: SiteFormState = {
|
state: SiteFormState = {
|
||||||
siteForm: {
|
siteForm: {
|
||||||
auth: "TODO",
|
auth: "TODO",
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
instance_select: {
|
||||||
|
allowed_instances: "",
|
||||||
|
blocked_instances: "",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: any, context: any) {
|
constructor(props: any, context: any) {
|
||||||
|
@ -554,44 +569,8 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
{this.state.siteForm.federation_enabled && (
|
{this.state.siteForm.federation_enabled && (
|
||||||
<>
|
<>
|
||||||
<div className="form-group row">
|
<div className="form-group row">
|
||||||
<label
|
{this.federatedInstanceSelect("allowed_instances")}
|
||||||
className="col-12 col-form-label"
|
{this.federatedInstanceSelect("blocked_instances")}
|
||||||
htmlFor="create-site-allowed-instances"
|
|
||||||
>
|
|
||||||
{i18n.t("allowed_instances")}
|
|
||||||
</label>
|
|
||||||
<div className="col-12">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="instance1.tld,instance2.tld"
|
|
||||||
id="create-site-allowed-instances"
|
|
||||||
className="form-control"
|
|
||||||
value={this.instancesToString(
|
|
||||||
this.state.siteForm.allowed_instances
|
|
||||||
)}
|
|
||||||
onInput={linkEvent(this, this.handleSiteAllowedInstances)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="form-group row">
|
|
||||||
<label
|
|
||||||
className="col-12 col-form-label"
|
|
||||||
htmlFor="create-site-blocked-instances"
|
|
||||||
>
|
|
||||||
{i18n.t("blocked_instances")}
|
|
||||||
</label>
|
|
||||||
<div className="col-12">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="instance1.tld,instance2.tld"
|
|
||||||
id="create-site-blocked-instances"
|
|
||||||
className="form-control"
|
|
||||||
value={this.instancesToString(
|
|
||||||
this.state.siteForm.blocked_instances
|
|
||||||
)}
|
|
||||||
onInput={linkEvent(this, this.handleSiteBlockedInstances)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group row">
|
<div className="form-group row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
|
@ -930,6 +909,86 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
federatedInstanceSelect(key: InstanceKey) {
|
||||||
|
const id = `create_site_${key}`;
|
||||||
|
const value = this.state.instance_select[key];
|
||||||
|
const selectedInstances = this.state.siteForm[key];
|
||||||
|
return (
|
||||||
|
<div className="col-12 col-md-6">
|
||||||
|
<label className="col-form-label" htmlFor={id}>
|
||||||
|
{i18n.t(key)}
|
||||||
|
</label>
|
||||||
|
<div className="d-flex justify-content-between align-items-center">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="instance.tld"
|
||||||
|
id={id}
|
||||||
|
className="form-control"
|
||||||
|
value={value}
|
||||||
|
onInput={linkEvent(key, this.handleInstanceTextChange)}
|
||||||
|
onKeyUp={linkEvent(key, this.handleInstanceEnterPress)}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="btn btn-sm bg-success ml-2"
|
||||||
|
onClick={linkEvent(key, this.handleAddInstance)}
|
||||||
|
tabIndex={
|
||||||
|
-1 /* Making this untabble because handling enter key in text input makes keyboard support for this button redundant */
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Icon icon="add" classes="icon-inline text-light m-auto" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{selectedInstances && selectedInstances.length > 0 && (
|
||||||
|
<ul className="mt-3 list-unstyled w-100 d-flex flex-column justify-content-around align-items-center">
|
||||||
|
{selectedInstances.map(instance => (
|
||||||
|
<li
|
||||||
|
key={instance}
|
||||||
|
className="my-1 w-100 w-md-75 d-flex align-items-center justify-content-between"
|
||||||
|
>
|
||||||
|
<label className="d-block m-0 w-100 " htmlFor={instance}>
|
||||||
|
<strong>{instance}</strong>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
id={instance}
|
||||||
|
type="button"
|
||||||
|
className="btn btn-sm bg-danger"
|
||||||
|
onClick={linkEvent(
|
||||||
|
{ key, instance },
|
||||||
|
this.handleRemoveInstance
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Icon icon="x" classes="icon-inline text-light m-auto" />
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInstanceTextChange(type: InstanceKey, event: any) {
|
||||||
|
this.setState(s => ({
|
||||||
|
...s,
|
||||||
|
instance_select: {
|
||||||
|
...s.instance_select,
|
||||||
|
[type]: event.target.value,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInstanceEnterPress(
|
||||||
|
key: InstanceKey,
|
||||||
|
event: InfernoKeyboardEvent<HTMLInputElement>
|
||||||
|
) {
|
||||||
|
if (event.code.toLowerCase() === "enter") {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
this.handleAddInstance(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handleCreateSiteSubmit(i: SiteForm, event: any) {
|
handleCreateSiteSubmit(i: SiteForm, event: any) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
i.setState({ loading: true });
|
i.setState({ loading: true });
|
||||||
|
@ -986,18 +1045,43 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
i.setState(i.state);
|
i.setState(i.state);
|
||||||
}
|
}
|
||||||
|
|
||||||
instancesToString(opt?: string[]): string {
|
handleAddInstance(key: InstanceKey) {
|
||||||
return opt ? opt.join(",") : "";
|
const instance = this.state.instance_select[key].trim();
|
||||||
|
if (!this.state.siteForm[key]?.includes(instance)) {
|
||||||
|
this.setState(s => ({
|
||||||
|
...s,
|
||||||
|
siteForm: {
|
||||||
|
...s.siteForm,
|
||||||
|
[key]: [...(s.siteForm[key] ?? []), instance],
|
||||||
|
},
|
||||||
|
instance_select: {
|
||||||
|
...s.instance_select,
|
||||||
|
[key]: "",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
const oppositeKey: InstanceKey =
|
||||||
|
key === "allowed_instances" ? "blocked_instances" : "allowed_instances";
|
||||||
|
if (this.state.siteForm[oppositeKey]?.includes(instance)) {
|
||||||
|
this.handleRemoveInstance({ key: oppositeKey, instance });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSiteAllowedInstances(i: SiteForm, event: any) {
|
handleRemoveInstance({
|
||||||
let list = splitToList(event.target.value);
|
key,
|
||||||
i.setState(s => ((s.siteForm.allowed_instances = list), s));
|
instance,
|
||||||
}
|
}: {
|
||||||
|
key: InstanceKey;
|
||||||
handleSiteBlockedInstances(i: SiteForm, event: any) {
|
instance: string;
|
||||||
let list = splitToList(event.target.value);
|
}) {
|
||||||
i.setState(s => ((s.siteForm.blocked_instances = list), s));
|
this.setState(s => ({
|
||||||
|
...s,
|
||||||
|
siteForm: {
|
||||||
|
...s.siteForm,
|
||||||
|
[key]: s.siteForm[key]?.filter(i => i !== instance),
|
||||||
|
},
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSiteNameChange(i: SiteForm, event: any) {
|
handleSiteNameChange(i: SiteForm, event: any) {
|
||||||
|
@ -1259,12 +1343,3 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
|
||||||
this.setState(s => ((s.siteForm.default_post_listing_type = val), s));
|
this.setState(s => ((s.siteForm.default_post_listing_type = val), s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function splitToList(commaList: string): string[] {
|
|
||||||
if (commaList !== "") {
|
|
||||||
let list = commaList.trim().split(",");
|
|
||||||
return list;
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -123,9 +123,12 @@ const createClientConfig = (_env, mode) => {
|
||||||
urlPattern: ({ url: { pathname, host }, sameOrigin }) =>
|
urlPattern: ({ url: { pathname, host }, sameOrigin }) =>
|
||||||
(sameOrigin || host.includes("localhost")) &&
|
(sameOrigin || host.includes("localhost")) &&
|
||||||
pathname.includes("static"),
|
pathname.includes("static"),
|
||||||
handler: "CacheFirst",
|
handler: mode === "development" ? "NetworkFirst" : "CacheFirst",
|
||||||
options: {
|
options: {
|
||||||
cacheName: "static-cache",
|
cacheName: "static-cache",
|
||||||
|
expiration: {
|
||||||
|
maxAgeSeconds: 60 * 60 * 24,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue