mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 05:52:25 -05:00 
			
		
		
		
	[feature] Allow editing domain blocks/allows, fix comment import (#3967)
* start implementing editing of existing domain permissions * [feature] Allow editing domain blocks/allows, fix comment import * [bugfix] Use "comment" via /api/v1/instance * fix the stuff
This commit is contained in:
		
					parent
					
						
							
								db4b857159
							
						
					
				
			
			
				commit
				
					
						b184432331
					
				
			
		
					 32 changed files with 1021 additions and 313 deletions
				
			
		|  | @ -40,39 +40,19 @@ function importEntriesProcessor(formData: ImportDomainPermsParams): (_entry: Dom | |||
| 
 | ||||
| 	// Override each obfuscate entry if necessary.
 | ||||
| 	if (formData.obfuscate !== undefined) { | ||||
| 		const obfuscateEntry = (entry: DomainPerm) => { | ||||
| 		processingFuncs.push((entry: DomainPerm) => { | ||||
| 			entry.obfuscate = formData.obfuscate; | ||||
| 		}; | ||||
| 		processingFuncs.push(obfuscateEntry); | ||||
| 		}); | ||||
| 	} | ||||
| 
 | ||||
| 	// Check whether we need to append or replace
 | ||||
| 	// private_comment and public_comment.
 | ||||
| 	// Check whether we need to replace
 | ||||
| 	// private_comment and/or public_comment.
 | ||||
| 	["private_comment","public_comment"].forEach((commentType) => { | ||||
| 		let text = formData.commentType?.trim(); | ||||
| 		if (!text) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		switch(formData[`${commentType}_behavior`]) { | ||||
| 			case "append": | ||||
| 				const appendComment = (entry: DomainPerm) => { | ||||
| 					if (entry.commentType == undefined) { | ||||
| 						entry.commentType = text; | ||||
| 					} else { | ||||
| 						entry.commentType = [entry.commentType, text].join("\n"); | ||||
| 					} | ||||
| 				}; | ||||
| 
 | ||||
| 				processingFuncs.push(appendComment); | ||||
| 				break; | ||||
| 			case "replace": | ||||
| 				const replaceComment = (entry: DomainPerm) => { | ||||
| 					entry.commentType = text; | ||||
| 				}; | ||||
| 
 | ||||
| 				processingFuncs.push(replaceComment); | ||||
| 				break; | ||||
| 		if (formData[`replace_${commentType}`]) { | ||||
| 			const text = formData[commentType]?.trim(); | ||||
| 			processingFuncs.push((entry: DomainPerm) => { | ||||
| 				entry[commentType] = text; | ||||
| 			}); | ||||
| 		} | ||||
| 	}); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ import { gtsApi } from "../../gts-api"; | |||
| import { | ||||
| 	replaceCacheOnMutation, | ||||
| 	removeFromCacheOnMutation, | ||||
| 	updateCacheOnMutation, | ||||
| } from "../../query-modifiers"; | ||||
| import { listToKeyedObject } from "../../transforms"; | ||||
| import type { | ||||
|  | @ -55,6 +56,36 @@ const extended = gtsApi.injectEndpoints({ | |||
| 			...replaceCacheOnMutation("domainAllows") | ||||
| 		}), | ||||
| 
 | ||||
| 		updateDomainBlock: build.mutation<DomainPerm, any>({ | ||||
| 			query: ({ id, ...formData}) => ({ | ||||
| 				method: "PUT", | ||||
| 				url: `/api/v1/admin/domain_blocks/${id}`, | ||||
| 				asForm: true, | ||||
| 				body: formData, | ||||
| 				discardEmpty: false | ||||
| 			}), | ||||
| 			...updateCacheOnMutation("domainBlocks", { | ||||
| 				key: (_draft, newData) => { | ||||
| 					return newData.domain; | ||||
| 				} | ||||
| 			}) | ||||
| 		}), | ||||
| 
 | ||||
| 		updateDomainAllow: build.mutation<DomainPerm, any>({ | ||||
| 			query: ({ id, ...formData}) => ({ | ||||
| 				method: "PUT", | ||||
| 				url: `/api/v1/admin/domain_allows/${id}`, | ||||
| 				asForm: true, | ||||
| 				body: formData, | ||||
| 				discardEmpty: false | ||||
| 			}), | ||||
| 			...updateCacheOnMutation("domainAllows", { | ||||
| 				key: (_draft, newData) => { | ||||
| 					return newData.domain; | ||||
| 				} | ||||
| 			}) | ||||
| 		}), | ||||
| 
 | ||||
| 		removeDomainBlock: build.mutation<DomainPerm, string>({ | ||||
| 			query: (id) => ({ | ||||
| 				method: "DELETE", | ||||
|  | @ -91,6 +122,16 @@ const useAddDomainBlockMutation = extended.useAddDomainBlockMutation; | |||
|  */ | ||||
| const useAddDomainAllowMutation = extended.useAddDomainAllowMutation; | ||||
| 
 | ||||
| /** | ||||
|  * Update a single domain permission (block) by PUTing to `/api/v1/admin/domain_blocks/{id}`. | ||||
|  */ | ||||
| const useUpdateDomainBlockMutation = extended.useUpdateDomainBlockMutation; | ||||
| 
 | ||||
| /** | ||||
|  * Update a single domain permission (allow) by PUTing to `/api/v1/admin/domain_allows/{id}`. | ||||
|  */ | ||||
| const useUpdateDomainAllowMutation = extended.useUpdateDomainAllowMutation; | ||||
| 
 | ||||
| /** | ||||
|  * Remove a single domain permission (block) by DELETEing to `/api/v1/admin/domain_blocks/{id}`. | ||||
|  */ | ||||
|  | @ -104,6 +145,8 @@ const useRemoveDomainAllowMutation = extended.useRemoveDomainAllowMutation; | |||
| export { | ||||
| 	useAddDomainBlockMutation, | ||||
| 	useAddDomainAllowMutation, | ||||
| 	useUpdateDomainBlockMutation, | ||||
| 	useUpdateDomainAllowMutation, | ||||
| 	useRemoveDomainBlockMutation, | ||||
| 	useRemoveDomainAllowMutation | ||||
| }; | ||||
|  |  | |||
|  | @ -46,8 +46,8 @@ export interface DomainPerm { | |||
| 	valid?: boolean; | ||||
| 	checked?: boolean; | ||||
| 	commentType?: string; | ||||
| 	private_comment_behavior?: "append" | "replace"; | ||||
| 	public_comment_behavior?: "append" | "replace"; | ||||
| 	replace_private_comment?: boolean; | ||||
| 	replace_public_comment?: boolean; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | @ -65,8 +65,8 @@ const domainPermStripOnImport: Set<keyof DomainPerm> = new Set([ | |||
| 	"valid", | ||||
| 	"checked", | ||||
| 	"commentType", | ||||
| 	"private_comment_behavior", | ||||
| 	"public_comment_behavior", | ||||
| 	"replace_private_comment", | ||||
| 	"replace_public_comment", | ||||
| ]); | ||||
| 
 | ||||
| /** | ||||
|  |  | |||
|  | @ -618,6 +618,15 @@ span.form-info { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| section > div.domain-block, | ||||
| section > div.domain-allow { | ||||
| 	height: 100%; | ||||
| 
 | ||||
| 	> a { | ||||
| 		margin-top: auto; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| .domain-permissions-list { | ||||
| 	p { | ||||
| 		margin-top: 0; | ||||
|  | @ -976,32 +985,26 @@ button.tab-button { | |||
| 
 | ||||
| .domain-perm-import-list { | ||||
| 	.checkbox-list-wrapper { | ||||
| 		overflow-x: auto; | ||||
| 		display: grid; | ||||
| 		gap: 1rem; | ||||
| 	} | ||||
| 
 | ||||
| 	.checkbox-list { | ||||
| 		overflow-x: auto; | ||||
| 
 | ||||
| 		.header { | ||||
| 			align-items: center; | ||||
| 			input[type="checkbox"] { | ||||
| 				align-self: start; | ||||
| 				height: 1.5rem; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		.entry { | ||||
| 			gap: 0; | ||||
| 			width: 100%; | ||||
| 			grid-template-columns: auto minmax(25ch, 2fr) minmax(40ch, 1fr); | ||||
| 			grid-template-rows: auto 1fr; | ||||
| 
 | ||||
| 			input[type="checkbox"] { | ||||
| 				margin-right: 1rem; | ||||
| 			} | ||||
| 			grid-template-columns: auto max(50%, 14rem) 1fr; | ||||
| 			column-gap: 1rem; | ||||
| 			align-items: center; | ||||
| 
 | ||||
| 			.domain-input { | ||||
| 				margin-right: 0.5rem; | ||||
| 				display: grid; | ||||
| 				grid-template-columns: 1fr $fa-fw; | ||||
| 				gap: 0.5rem; | ||||
|  | @ -1020,13 +1023,21 @@ button.tab-button { | |||
| 			} | ||||
| 
 | ||||
| 			p { | ||||
| 				align-self: center; | ||||
| 				margin: 0; | ||||
| 				grid-column: 4; | ||||
| 				grid-row: 1 / span 2; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	.set-comment-checkbox { | ||||
| 		display: flex; | ||||
| 		flex-direction: column; | ||||
| 		gap: 0.25rem; | ||||
| 
 | ||||
| 		padding: 0.5rem 1rem 1rem 1rem; | ||||
| 		width: 100%; | ||||
| 		border: 0.1rem solid var(--gray1); | ||||
| 		border-radius: 0.1rem; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| .import-export { | ||||
|  | @ -1406,6 +1417,7 @@ button.tab-button { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| .domain-permission-details, | ||||
| .domain-permission-draft-details, | ||||
| .domain-permission-exclude-details, | ||||
| .domain-permission-subscription-details { | ||||
|  | @ -1414,6 +1426,7 @@ button.tab-button { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| .domain-permission-details, | ||||
| .domain-permission-drafts-view, | ||||
| .domain-permission-draft-details, | ||||
| .domain-permission-subscriptions-view, | ||||
|  |  | |||
|  | @ -32,8 +32,18 @@ import Loading from "../../../components/loading"; | |||
| import BackButton from "../../../components/back-button"; | ||||
| import MutationButton from "../../../components/form/mutation-button"; | ||||
| 
 | ||||
| import { useDomainAllowsQuery, useDomainBlocksQuery } from "../../../lib/query/admin/domain-permissions/get"; | ||||
| import { useAddDomainAllowMutation, useAddDomainBlockMutation, useRemoveDomainAllowMutation, useRemoveDomainBlockMutation } from "../../../lib/query/admin/domain-permissions/update"; | ||||
| import {  | ||||
| 	useDomainAllowsQuery, | ||||
| 	useDomainBlocksQuery, | ||||
| } from "../../../lib/query/admin/domain-permissions/get"; | ||||
| import { | ||||
| 	useAddDomainAllowMutation, | ||||
| 	useAddDomainBlockMutation, | ||||
| 	useRemoveDomainAllowMutation, | ||||
| 	useRemoveDomainBlockMutation, | ||||
| 	useUpdateDomainAllowMutation, | ||||
| 	useUpdateDomainBlockMutation, | ||||
| } from "../../../lib/query/admin/domain-permissions/update"; | ||||
| import { DomainPerm } from "../../../lib/types/domain-permission"; | ||||
| import { NoArg } from "../../../lib/types/query"; | ||||
| import { Error } from "../../../components/error"; | ||||
|  | @ -41,8 +51,10 @@ import { useBaseUrl } from "../../../lib/navigation/util"; | |||
| import { PermType } from "../../../lib/types/perm"; | ||||
| import { useCapitalize } from "../../../lib/util"; | ||||
| import { formDomainValidator } from "../../../lib/util/formvalidators"; | ||||
| import UsernameLozenge from "../../../components/username-lozenge"; | ||||
| import { FormSubmitEvent } from "../../../lib/form/types"; | ||||
| 
 | ||||
| export default function DomainPermDetail() { | ||||
| export default function DomainPermView() { | ||||
| 	const baseUrl = useBaseUrl(); | ||||
| 	const search = useSearch(); | ||||
| 
 | ||||
|  | @ -101,33 +113,16 @@ export default function DomainPermDetail() { | |||
| 		? blocks[domain] | ||||
| 		: allows[domain]; | ||||
| 	 | ||||
| 	// Render different into content depending on
 | ||||
| 	// if we have a perm already for this domain.
 | ||||
| 	let infoContent: React.JSX.Element; | ||||
| 	if (existingPerm === undefined) { | ||||
| 		infoContent = ( | ||||
| 			<span> | ||||
| 				No stored {permType} yet, you can add one below: | ||||
| 			</span> | ||||
| 		); | ||||
| 	} else { | ||||
| 		infoContent = ( | ||||
| 			<div className="info"> | ||||
| 				<i className="fa fa-fw fa-exclamation-triangle" aria-hidden="true"></i> | ||||
| 				<b>Editing existing domain {permTypeRaw} isn't implemented yet, <a href="https://github.com/superseriousbusiness/gotosocial/issues/1198" target="_blank" rel="noopener noreferrer">check here for progress</a></b> | ||||
| 			</div> | ||||
| 		); | ||||
| 	} | ||||
| 	const title = <span>Domain {permType} for {domain}</span>; | ||||
| 
 | ||||
| 	return ( | ||||
| 		<div> | ||||
| 			<h1 className="text-cutoff"> | ||||
| 				<BackButton to={`~${baseUrl}/${permTypeRaw}`} /> | ||||
| 				{" "} | ||||
| 				Domain {permType} for {domain} | ||||
| 			</h1> | ||||
| 			{infoContent} | ||||
| 			<DomainPermForm | ||||
| 		<div className="domain-permission-details"> | ||||
| 			<h1><BackButton to={`~${baseUrl}/${permTypeRaw}`} /> {title}</h1> | ||||
| 			{ existingPerm | ||||
| 				? <DomainPermDetails perm={existingPerm} permType={permType} /> | ||||
| 				: <span>No stored {permType} yet, you can add one below:</span> | ||||
| 			} | ||||
| 			<CreateOrUpdateDomainPerm | ||||
| 				defaultDomain={domain} | ||||
| 				perm={existingPerm} | ||||
| 				permType={permType} | ||||
|  | @ -136,23 +131,75 @@ export default function DomainPermDetail() { | |||
| 	); | ||||
| } | ||||
| 
 | ||||
| interface DomainPermFormProps { | ||||
| interface DomainPermDetailsProps { | ||||
| 	perm: DomainPerm, | ||||
| 	permType: PermType, | ||||
| } | ||||
| 
 | ||||
| function DomainPermDetails({ | ||||
| 	perm, | ||||
| 	permType | ||||
| }: DomainPermDetailsProps) { | ||||
| 	const baseUrl = useBaseUrl(); | ||||
| 	const [ location ] = useLocation(); | ||||
| 	 | ||||
| 	const created = useMemo(() => { | ||||
| 		if (perm.created_at) { | ||||
| 			return new Date(perm.created_at).toDateString(); | ||||
| 		} | ||||
| 		return "unknown"; | ||||
| 	}, [perm.created_at]); | ||||
| 
 | ||||
| 	return ( | ||||
| 		<dl className="info-list"> | ||||
| 			<div className="info-list-entry"> | ||||
| 				<dt>Created</dt> | ||||
| 				<dd><time dateTime={perm.created_at}>{created}</time></dd> | ||||
| 			</div> | ||||
| 			<div className="info-list-entry"> | ||||
| 				<dt>Created By</dt> | ||||
| 				<dd> | ||||
| 					<UsernameLozenge | ||||
| 						account={perm.created_by} | ||||
| 						linkTo={`~/settings/moderation/accounts/${perm.created_by}`} | ||||
| 						backLocation={`~${baseUrl}${location}`} | ||||
| 					/> | ||||
| 				</dd> | ||||
| 			</div> | ||||
| 			<div className="info-list-entry"> | ||||
| 				<dt>Domain</dt> | ||||
| 				<dd>{perm.domain}</dd> | ||||
| 			</div> | ||||
| 			<div className="info-list-entry"> | ||||
| 				<dt>Permission type</dt> | ||||
| 				<dd className={`permission-type ${permType}`}> | ||||
| 					<i | ||||
| 						aria-hidden={true} | ||||
| 						className={`fa fa-${permType === "allow" ? "check" : "close"}`} | ||||
| 					></i> | ||||
| 					{permType} | ||||
| 				</dd> | ||||
| 			</div> | ||||
| 			<div className="info-list-entry"> | ||||
| 				<dt>Subscription ID</dt> | ||||
| 				<dd>{perm.subscription_id ?? "[none]"}</dd> | ||||
| 			</div> | ||||
| 		</dl> | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
| interface CreateOrUpdateDomainPermProps { | ||||
| 	defaultDomain: string; | ||||
| 	perm?: DomainPerm; | ||||
| 	permType: PermType; | ||||
| } | ||||
| 
 | ||||
| function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps) { | ||||
| function CreateOrUpdateDomainPerm({ | ||||
| 	defaultDomain, | ||||
| 	perm, | ||||
| 	permType | ||||
| }: CreateOrUpdateDomainPermProps) { | ||||
| 	const isExistingPerm = perm !== undefined; | ||||
| 	const disabledForm = isExistingPerm | ||||
| 		? { | ||||
| 			disabled: true, | ||||
| 			title: "Domain permissions currently cannot be edited." | ||||
| 		} | ||||
| 		: { | ||||
| 			disabled: false, | ||||
| 			title: "", | ||||
| 		}; | ||||
| 
 | ||||
| 	const form = { | ||||
| 		domain: useTextInput("domain", { | ||||
|  | @ -161,8 +208,8 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps) | |||
| 			validator: formDomainValidator, | ||||
| 		}), | ||||
| 		obfuscate: useBoolInput("obfuscate", { source: perm }), | ||||
| 		commentPrivate: useTextInput("private_comment", { source: perm }), | ||||
| 		commentPublic: useTextInput("public_comment", { source: perm }) | ||||
| 		privateComment: useTextInput("private_comment", { source: perm }), | ||||
| 		publicComment: useTextInput("public_comment", { source: perm }) | ||||
| 	}; | ||||
| 
 | ||||
| 	// Check which perm type we're meant to be handling
 | ||||
|  | @ -171,112 +218,132 @@ function DomainPermForm({ defaultDomain, perm, permType }: DomainPermFormProps) | |||
| 	// react is like "weh" (mood), but we can decide
 | ||||
| 	// which ones to use conditionally.
 | ||||
| 	const [ addBlock, addBlockResult ] = useAddDomainBlockMutation(); | ||||
| 	const [ updateBlock, updateBlockResult ] = useUpdateDomainBlockMutation({ fixedCacheKey: perm?.id }); | ||||
| 	const [ removeBlock, removeBlockResult] = useRemoveDomainBlockMutation({ fixedCacheKey: perm?.id }); | ||||
| 	const [ addAllow, addAllowResult ] = useAddDomainAllowMutation(); | ||||
| 	const [ updateAllow, updateAllowResult ] = useUpdateDomainAllowMutation({ fixedCacheKey: perm?.id }); | ||||
| 	const [ removeAllow, removeAllowResult ] = useRemoveDomainAllowMutation({ fixedCacheKey: perm?.id }); | ||||
| 	 | ||||
| 	const [ | ||||
| 		addTrigger, | ||||
| 		addResult, | ||||
| 		createOrUpdateTrigger, | ||||
| 		createOrUpdateResult, | ||||
| 		removeTrigger, | ||||
| 		removeResult, | ||||
| 	] = useMemo(() => { | ||||
| 		return permType == "block" | ||||
| 			? [ | ||||
| 				addBlock, | ||||
| 				addBlockResult, | ||||
| 				removeBlock, | ||||
| 				removeBlockResult, | ||||
| 			] | ||||
| 			: [ | ||||
| 				addAllow, | ||||
| 				addAllowResult, | ||||
| 				removeAllow, | ||||
| 				removeAllowResult, | ||||
| 			]; | ||||
| 	}, [permType, | ||||
| 		addBlock, addBlockResult, removeBlock, removeBlockResult, | ||||
| 		addAllow, addAllowResult, removeAllow, removeAllowResult, | ||||
| 		switch (true) { | ||||
| 			case (permType === "block" && !isExistingPerm): | ||||
| 				return [ addBlock, addBlockResult, removeBlock, removeBlockResult ]; | ||||
| 			case (permType === "block"): | ||||
| 				return [ updateBlock, updateBlockResult, removeBlock, removeBlockResult ]; | ||||
| 			case !isExistingPerm: | ||||
| 				return [ addAllow, addAllowResult, removeAllow, removeAllowResult ]; | ||||
| 			default: | ||||
| 				return [ updateAllow, updateAllowResult, removeAllow, removeAllowResult ]; | ||||
| 		} | ||||
| 	}, [permType, isExistingPerm, | ||||
| 		addBlock, addBlockResult, updateBlock, updateBlockResult, removeBlock, removeBlockResult, | ||||
| 		addAllow, addAllowResult, updateAllow, updateAllowResult, removeAllow, removeAllowResult, | ||||
| 	]); | ||||
| 
 | ||||
| 	// Use appropriate submission params for this permType.
 | ||||
| 	const [submitForm, submitFormResult] = useFormSubmit(form, [addTrigger, addResult], { changedOnly: false }); | ||||
| 	// Use appropriate submission params for this
 | ||||
| 	// permType, and whether we're creating or updating.
 | ||||
| 	const [submit, submitResult] = useFormSubmit( | ||||
| 		form, | ||||
| 		[ createOrUpdateTrigger, createOrUpdateResult ], | ||||
| 		{ | ||||
| 			changedOnly: isExistingPerm, | ||||
| 			// If we're updating an existing perm,
 | ||||
| 			// insert the perm ID into the mutation
 | ||||
| 			// data before submitting. Otherwise just
 | ||||
| 			// return the mutationData unmodified.
 | ||||
| 			customizeMutationArgs: (mutationData) => { | ||||
| 				if (isExistingPerm) { | ||||
| 					return { | ||||
| 						id: perm?.id, | ||||
| 						...mutationData, | ||||
| 					}; | ||||
| 				} else { | ||||
| 					return mutationData; | ||||
| 				} | ||||
| 			}, | ||||
| 		}, | ||||
| 	); | ||||
| 
 | ||||
| 	// Uppercase first letter of given permType.
 | ||||
| 	const permTypeUpper = useCapitalize(permType); | ||||
| 
 | ||||
| 	const [location, setLocation] = useLocation(); | ||||
| 
 | ||||
| 	function verifyUrlThenSubmit(e) { | ||||
| 	function onSubmit(e: FormSubmitEvent) { | ||||
| 		// Adding a new domain permissions happens on a url like
 | ||||
| 		// "/settings/admin/domain-permissions/:permType/domain.com",
 | ||||
| 		// but if domain input changes, that doesn't match anymore
 | ||||
| 		// and causes issues later on so, before submitting the form,
 | ||||
| 		// silently change url, and THEN submit.
 | ||||
| 		let correctUrl = `/${permType}s/${form.domain.value}`; | ||||
| 		if (location != correctUrl) { | ||||
| 			setLocation(correctUrl); | ||||
| 		if (!isExistingPerm) { | ||||
| 			let correctUrl = `/${permType}s/${form.domain.value}`; | ||||
| 			if (location != correctUrl) { | ||||
| 				setLocation(correctUrl); | ||||
| 			} | ||||
| 		} | ||||
| 		return submitForm(e); | ||||
| 		return submit(e); | ||||
| 	} | ||||
| 
 | ||||
| 	return ( | ||||
| 		<form onSubmit={verifyUrlThenSubmit}> | ||||
| 			<TextInput | ||||
| 				field={form.domain} | ||||
| 				label="Domain" | ||||
| 				placeholder="example.com" | ||||
| 				autoCapitalize="none" | ||||
| 				spellCheck="false" | ||||
| 				{...disabledForm} | ||||
| 			/> | ||||
| 		<form onSubmit={onSubmit}> | ||||
| 			{ !isExistingPerm &&  | ||||
| 				<TextInput | ||||
| 					field={form.domain} | ||||
| 					label="Domain" | ||||
| 					placeholder="example.com" | ||||
| 					autoCapitalize="none" | ||||
| 					spellCheck="false" | ||||
| 				/> | ||||
| 			} | ||||
| 
 | ||||
| 			<Checkbox | ||||
| 				field={form.obfuscate} | ||||
| 				label="Obfuscate domain in public lists" | ||||
| 				{...disabledForm} | ||||
| 			/> | ||||
| 
 | ||||
| 			<TextArea | ||||
| 				field={form.commentPrivate} | ||||
| 				field={form.privateComment} | ||||
| 				label="Private comment" | ||||
| 				autoCapitalize="sentences" | ||||
| 				rows={3} | ||||
| 				{...disabledForm} | ||||
| 			/> | ||||
| 
 | ||||
| 			<TextArea | ||||
| 				field={form.commentPublic} | ||||
| 				field={form.publicComment} | ||||
| 				label="Public comment" | ||||
| 				autoCapitalize="sentences" | ||||
| 				rows={3} | ||||
| 				{...disabledForm} | ||||
| 			/> | ||||
| 
 | ||||
| 			<div className="action-buttons row"> | ||||
| 				<MutationButton | ||||
| 					label={permTypeUpper} | ||||
| 					result={submitFormResult} | ||||
| 					showError={false} | ||||
| 					{...disabledForm} | ||||
| 					label={isExistingPerm ? "Update " + permType.toString() : permTypeUpper} | ||||
| 					result={submitResult} | ||||
| 					disabled={ | ||||
| 						isExistingPerm && | ||||
| 						!form.obfuscate.hasChanged() && | ||||
| 						!form.privateComment.hasChanged() && | ||||
| 						!form.publicComment.hasChanged() | ||||
| 					} | ||||
| 				/> | ||||
| 
 | ||||
| 				{ | ||||
| 					isExistingPerm && | ||||
| 					<MutationButton | ||||
| 				{ isExistingPerm && | ||||
| 					<button | ||||
| 						type="button" | ||||
| 						onClick={() => removeTrigger(perm.id?? "")} | ||||
| 						label="Remove" | ||||
| 						result={removeResult} | ||||
| 						className="button danger" | ||||
| 						showError={false} | ||||
| 						disabled={!isExistingPerm} | ||||
| 					/> | ||||
| 					> | ||||
| 						Remove {permType.toString()} | ||||
| 					</button> | ||||
| 				} | ||||
| 			</div> | ||||
| 
 | ||||
| 			<> | ||||
| 				{addResult.error && <Error error={addResult.error} />} | ||||
| 				{createOrUpdateResult.error && <Error error={createOrUpdateResult.error} />} | ||||
| 				{removeResult.error && <Error error={removeResult.error} />} | ||||
| 			</> | ||||
| 
 | ||||
|  |  | |||
|  | @ -61,7 +61,7 @@ export default function ImportExport() { | |||
| 									> | ||||
| 										< back | ||||
| 									</span> | ||||
| 									  Confirm import of domain {form.permType.value}s: | ||||
| 									  Confirm {form.permType.value}s: | ||||
| 								</h1> | ||||
| 								<ProcessImport | ||||
| 									list={parseResult.data} | ||||
|  |  | |||
|  | @ -24,14 +24,12 @@ import { isValidDomainPermission, hasBetterScope } from "../../../lib/util/domai | |||
| import { | ||||
| 	useTextInput, | ||||
| 	useBoolInput, | ||||
| 	useRadioInput, | ||||
| 	useCheckListInput, | ||||
| } from "../../../lib/form"; | ||||
| 
 | ||||
| import { | ||||
| 	Select, | ||||
| 	TextArea, | ||||
| 	RadioGroup, | ||||
| 	Checkbox, | ||||
| 	TextInput, | ||||
| } from "../../../components/form/inputs"; | ||||
|  | @ -113,84 +111,81 @@ function ImportList({ list, data: domainPerms, permType }: ImportListProps) { | |||
| 		privateComment: useTextInput("private_comment", { | ||||
| 			defaultValue: `Imported on ${new Date().toLocaleString()}` | ||||
| 		}), | ||||
| 		privateCommentBehavior: useRadioInput("private_comment_behavior", { | ||||
| 			defaultValue: "append", | ||||
| 			options: { | ||||
| 				append: "Append to", | ||||
| 				replace: "Replace" | ||||
| 			} | ||||
| 		}), | ||||
| 		replacePrivateComment: useBoolInput("replace_private_comment", { defaultValue: false }), | ||||
| 		publicComment: useTextInput("public_comment"), | ||||
| 		publicCommentBehavior: useRadioInput("public_comment_behavior", { | ||||
| 			defaultValue: "append", | ||||
| 			options: { | ||||
| 				append: "Append to", | ||||
| 				replace: "Replace" | ||||
| 			} | ||||
| 		}), | ||||
| 		replacePublicComment: useBoolInput("replace_public_comment", { defaultValue: false }), | ||||
| 		permType: permType, | ||||
| 	}; | ||||
| 
 | ||||
| 	const [importDomains, importResult] = useFormSubmit(form, useImportDomainPermsMutation(), { changedOnly: false }); | ||||
| 	const [importDomains, importResult] = useFormSubmit( | ||||
| 		form, | ||||
| 		useImportDomainPermsMutation(), | ||||
| 		{ changedOnly: false }, | ||||
| 	); | ||||
| 
 | ||||
| 	return ( | ||||
| 		<> | ||||
| 			<form | ||||
| 				onSubmit={importDomains} | ||||
| 				className="domain-perm-import-list" | ||||
| 			> | ||||
| 				<span>{list.length} domain{list.length != 1 ? "s" : ""} in this list</span> | ||||
| 		<form | ||||
| 			onSubmit={importDomains} | ||||
| 			className="domain-perm-import-list" | ||||
| 		> | ||||
| 			<span>{list.length} domain{list.length != 1 ? "s" : ""} in this list</span> | ||||
| 
 | ||||
| 				{hasComment.both && | ||||
| 			{hasComment.both && | ||||
| 					<Select field={showComment} options={ | ||||
| 						<> | ||||
| 							<option value="public_comment">Show public comments</option> | ||||
| 							<option value="private_comment">Show private comments</option> | ||||
| 						</> | ||||
| 					} /> | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 				<div className="checkbox-list-wrapper"> | ||||
| 					<DomainCheckList | ||||
| 						field={form.domains} | ||||
| 						domainPerms={domainPerms} | ||||
| 						commentType={showComment.value as "public_comment" | "private_comment"} | ||||
| 						permType={form.permType} | ||||
| 					/> | ||||
| 				</div> | ||||
| 			<div className="checkbox-list-wrapper"> | ||||
| 				<DomainCheckList | ||||
| 					field={form.domains} | ||||
| 					domainPerms={domainPerms} | ||||
| 					commentType={showComment.value as "public_comment" | "private_comment"} | ||||
| 					permType={form.permType} | ||||
| 				/> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<Checkbox | ||||
| 				field={form.obfuscate} | ||||
| 				label="Obfuscate domains in public lists" | ||||
| 			/> | ||||
| 
 | ||||
| 			<div className="set-comment-checkbox"> | ||||
| 				<Checkbox | ||||
| 					field={form.replacePrivateComment} | ||||
| 					label="Set/replace private comment(s) to:" | ||||
| 				/> | ||||
| 				<TextArea | ||||
| 					field={form.privateComment} | ||||
| 					label="Private comment" | ||||
| 					rows={3} | ||||
| 					disabled={!form.replacePrivateComment.value} | ||||
| 					placeholder="Private comment" | ||||
| 				/> | ||||
| 				<RadioGroup | ||||
| 					field={form.privateCommentBehavior} | ||||
| 					label="imported private comment" | ||||
| 				/> | ||||
| 			</div> | ||||
| 
 | ||||
| 			<div className="set-comment-checkbox"> | ||||
| 				<Checkbox | ||||
| 					field={form.replacePublicComment} | ||||
| 					label="Set/replace public comment(s) to:" | ||||
| 				/> | ||||
| 				<TextArea | ||||
| 					field={form.publicComment} | ||||
| 					label="Public comment" | ||||
| 					rows={3} | ||||
| 					disabled={!form.replacePublicComment.value} | ||||
| 					placeholder="Public comment" | ||||
| 				/> | ||||
| 				<RadioGroup | ||||
| 					field={form.publicCommentBehavior} | ||||
| 					label="imported public comment" | ||||
| 				/> | ||||
| 			</div> | ||||
| 
 | ||||
| 				<Checkbox | ||||
| 					field={form.obfuscate} | ||||
| 					label="Obfuscate domains in public lists" | ||||
| 				/> | ||||
| 
 | ||||
| 				<MutationButton | ||||
| 					label="Import" | ||||
| 					disabled={false} | ||||
| 					result={importResult} | ||||
| 				/> | ||||
| 			</form> | ||||
| 		</> | ||||
| 			<MutationButton | ||||
| 				label="Import" | ||||
| 				disabled={false} | ||||
| 				result={importResult} | ||||
| 			/> | ||||
| 		</form> | ||||
| 	); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ import ReportDetail from "./reports/detail"; | |||
| import { ErrorBoundary } from "../../lib/navigation/error"; | ||||
| import ImportExport from "./domain-permissions/import-export"; | ||||
| import DomainPermissionsOverview from "./domain-permissions/overview"; | ||||
| import DomainPermDetail from "./domain-permissions/detail"; | ||||
| import DomainPermView from "./domain-permissions/detail"; | ||||
| import AccountsSearch from "./accounts"; | ||||
| import AccountsPending from "./accounts/pending"; | ||||
| import AccountDetail from "./accounts/detail"; | ||||
|  | @ -160,7 +160,7 @@ function ModerationDomainPermsRouter() { | |||
| 						<Route path="/subscriptions/preview" component={DomainPermissionSubscriptionsPreview} /> | ||||
| 						<Route path="/subscriptions/:permSubId" component={DomainPermissionSubscriptionDetail} /> | ||||
| 						<Route path="/:permType" component={DomainPermissionsOverview} /> | ||||
| 						<Route path="/:permType/:domain" component={DomainPermDetail} /> | ||||
| 						<Route path="/:permType/:domain" component={DomainPermView} /> | ||||
| 						<Route><Redirect to="/blocks"/></Route> | ||||
| 					</Switch> | ||||
| 				</ErrorBoundary> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue