diff options
| author | 2023-02-06 09:19:56 +0100 | |
|---|---|---|
| committer | 2023-02-06 09:19:56 +0100 | |
| commit | 47daddc10c291ec67320dd2485bffc498ea44bdf (patch) | |
| tree | 530677541399c27cd292dfc0050a71273c35f098 | |
| parent | [chore]: Bump codeberg.org/gruf/go-runners from 1.4.0 to 1.5.1 (#1428) (diff) | |
| download | gotosocial-47daddc10c291ec67320dd2485bffc498ea44bdf.tar.xz | |
[chore/frogend] Restructure form data default values / update from Query data (#1422)
* eslint: set console use to error to catch debug littering in CI
* remove debug logging
* some form field restructuring, fixes submitted updates not being reflected
* more form field restructuring
* remove debug logger
* simplify field updates
* fix react state set during render when submitting import file
* className instead of class
* show Select hints again
19 files changed, 153 insertions, 86 deletions
| diff --git a/web/source/.eslintrc.js b/web/source/.eslintrc.js index 81a2c39f9..0d30f742c 100644 --- a/web/source/.eslintrc.js +++ b/web/source/.eslintrc.js @@ -22,6 +22,7 @@ module.exports = {  	"extends": ["@joepie91/eslint-config/react"],  	"plugins": ["license-header"],  	"rules": { -		"license-header/header": ["error", __dirname + "/.license-header.js"] +		"license-header/header": ["error", __dirname + "/.license-header.js"], +		"no-console": 'error'  	}  };
\ No newline at end of file diff --git a/web/source/package.json b/web/source/package.json index 9e7951620..4f7221eb1 100644 --- a/web/source/package.json +++ b/web/source/package.json @@ -14,6 +14,7 @@      "@reduxjs/toolkit": "^1.8.6",      "ariakit": "^2.0.0-next.41",      "bluebird": "^3.7.2", +    "get-by-dot": "^1.0.2",      "is-valid-domain": "^0.1.6",      "js-file-download": "^0.4.12",      "langs": "^2.0.0", diff --git a/web/source/settings/admin/emoji/local/detail.js b/web/source/settings/admin/emoji/local/detail.js index cecd36869..8fcb5510c 100644 --- a/web/source/settings/admin/emoji/local/detail.js +++ b/web/source/settings/admin/emoji/local/detail.js @@ -54,7 +54,7 @@ module.exports = function EmojiDetailRoute() {  function EmojiDetailForm({ data: emoji }) {  	const form = {  		id: useValue("id", emoji.id), -		category: useComboBoxInput("category", { defaultValue: emoji.category }), +		category: useComboBoxInput("category", { source: emoji }),  		image: useFileInput("image", {  			withPreview: true,  			maxSize: 50 * 1024 // TODO: get from instance api diff --git a/web/source/settings/admin/federation/detail.js b/web/source/settings/admin/federation/detail.js index ecace90cd..ea9109720 100644 --- a/web/source/settings/admin/federation/detail.js +++ b/web/source/settings/admin/federation/detail.js @@ -19,7 +19,7 @@  "use strict";  const React = require("react"); -const { useRoute, Redirect } = require("wouter"); +const { useRoute, Redirect, useLocation } = require("wouter");  const query = require("../../lib/query"); @@ -69,12 +69,12 @@ module.exports = function InstanceDetail({ baseUrl }) {  		<div>  			<h1 className="text-cutoff"><BackButton to={baseUrl} /> Federation settings for: <span title={domain}>{domain}</span></h1>  			{infoContent} -			<DomainBlockForm defaultDomain={domain} block={existingBlock} /> +			<DomainBlockForm defaultDomain={domain} block={existingBlock} baseUrl={baseUrl} />  		</div>  	);  }; -function DomainBlockForm({ defaultDomain, block = {} }) { +function DomainBlockForm({ defaultDomain, block = {}, baseUrl }) {  	const isExistingBlock = block.domain != undefined;  	const disabledForm = isExistingBlock @@ -85,18 +85,31 @@ function DomainBlockForm({ defaultDomain, block = {} }) {  		: {};  	const form = { -		domain: useTextInput("domain", { defaultValue: block.domain ?? defaultDomain }), -		obfuscate: useBoolInput("obfuscate", { defaultValue: block.obfuscate }), -		commentPrivate: useTextInput("private_comment", { defaultValue: block.private_comment }), -		commentPublic: useTextInput("public_comment", { defaultValue: block.public_comment }) +		domain: useTextInput("domain", { source: block, defaultValue: defaultDomain }), +		obfuscate: useBoolInput("obfuscate", { source: block }), +		commentPrivate: useTextInput("private_comment", { source: block }), +		commentPublic: useTextInput("public_comment", { source: block })  	};  	const [submitForm, addResult] = useFormSubmit(form, query.useAddInstanceBlockMutation(), { changedOnly: false });  	const [removeBlock, removeResult] = query.useRemoveInstanceBlockMutation({ fixedCacheKey: block.id }); +	const [location, setLocation] = useLocation(); + +	function verifyUrlThenSubmit(e) { +		// Adding a new block happens on /settings/admin/federation/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, then submit +		let correctUrl = `${baseUrl}/${form.domain.value}`; +		if (location != correctUrl) { +			setLocation(correctUrl); +		} +		return submitForm(e); +	} +  	return ( -		<form onSubmit={submitForm}> +		<form onSubmit={verifyUrlThenSubmit}>  			<TextInput  				field={form.domain}  				label="Domain" diff --git a/web/source/settings/admin/federation/import-export/form.jsx b/web/source/settings/admin/federation/import-export/form.jsx index afd2d775d..7b6ad9206 100644 --- a/web/source/settings/admin/federation/import-export/form.jsx +++ b/web/source/settings/admin/federation/import-export/form.jsx @@ -36,13 +36,11 @@ const ExportFormatTable = require("./export-format-table");  module.exports = function ImportExportForm({ form, submitParse, parseResult }) {  	const [submitExport, exportResult] = useFormSubmit(form, query.useExportDomainListMutation()); -	const [updateFromFile, setUpdateFromFile] = React.useState(false); -  	function fileChanged(e) {  		const reader = new FileReader();  		reader.onload = function (read) { -			form.domains.setter(read.target.result); -			setUpdateFromFile(true); +			form.domains.value = read.target.result; +			submitParse();  		};  		reader.readAsText(e.target.files[0]);  	} @@ -54,10 +52,6 @@ module.exports = function ImportExportForm({ form, submitParse, parseResult }) {  		/* eslint-disable-next-line react-hooks/exhaustive-deps */  	}, [exportResult]); -	if (updateFromFile) { -		setUpdateFromFile(false); -		submitParse(); -	}  	return (  		<>  			<h1>Import / Export suspended domains</h1> diff --git a/web/source/settings/admin/federation/import-export/index.jsx b/web/source/settings/admin/federation/import-export/index.jsx index 3039b98f3..ca55296f8 100644 --- a/web/source/settings/admin/federation/import-export/index.jsx +++ b/web/source/settings/admin/federation/import-export/index.jsx @@ -40,7 +40,7 @@ module.exports = function ImportExport() {  		exportType: useTextInput("exportType", { defaultValue: "plain", dontReset: true })  	}; -	const [submitParse, parseResult] = useFormSubmit(form, query.useProcessDomainListMutation()); +	const [submitParse, parseResult] = useFormSubmit(form, query.useProcessDomainListMutation(), { changedOnly: false });  	const [_location, setLocation] = useLocation(); diff --git a/web/source/settings/admin/federation/import-export/process.jsx b/web/source/settings/admin/federation/import-export/process.jsx index 0b2d10099..6b9d98f01 100644 --- a/web/source/settings/admin/federation/import-export/process.jsx +++ b/web/source/settings/admin/federation/import-export/process.jsx @@ -234,7 +234,7 @@ const UpdateableEntry = React.memo(  		return (  			<>  				<span className="text-cutoff">{entry.domain}</span> -				<i class="fa fa-long-arrow-right" aria-hidden="true"></i> +				<i className="fa fa-long-arrow-right" aria-hidden="true"></i>  				<span>{entry.suggest}</span>  				<a role="button" onClick={() =>  					updateEntry(entry.key, { domain: entry.suggest, suggest: null }) diff --git a/web/source/settings/admin/settings.js b/web/source/settings/admin/settings.js index c0a9eabbe..fa0085946 100644 --- a/web/source/settings/admin/settings.js +++ b/web/source/settings/admin/settings.js @@ -49,14 +49,17 @@ module.exports = function AdminSettings() {  function AdminSettingsForm({ data: instance }) {  	const form = { -		title: useTextInput("title", { defaultValue: instance.title }), +		title: useTextInput("title", { +			source: instance, +			validator: (val) => val.length <= 40 ? "" : "Instance title must be 40 characters or less" +		}),  		thumbnail: useFileInput("thumbnail", { withPreview: true }), -		thumbnailDesc: useTextInput("thumbnail_description", { defaultValue: instance.thumbnail_description }), -		shortDesc: useTextInput("short_description", { defaultValue: instance.short_description }), -		description: useTextInput("description", { defaultValue: instance.description }), -		contactUser: useTextInput("contact_username", { defaultValue: instance.contact_account?.username }), -		contactEmail: useTextInput("contact_email", { defaultValue: instance.email }), -		terms: useTextInput("terms", { defaultValue: instance.terms }) +		thumbnailDesc: useTextInput("thumbnail_description", { source: instance }), +		shortDesc: useTextInput("short_description", { source: instance }), +		description: useTextInput("description", { source: instance }), +		contactUser: useTextInput("contact_username", { source: instance, valueSelector: (s) => s.contact_account?.username }), +		contactEmail: useTextInput("contact_email", { source: instance, valueSelector: (s) => s.email }), +		terms: useTextInput("terms", { source: instance })  	};  	const [submitForm, result] = useFormSubmit(form, query.useUpdateInstanceMutation()); diff --git a/web/source/settings/components/form/inputs.jsx b/web/source/settings/components/form/inputs.jsx index 19386b6f2..8694d7b73 100644 --- a/web/source/settings/components/form/inputs.jsx +++ b/web/source/settings/components/form/inputs.jsx @@ -22,7 +22,6 @@ const React = require("react");  function TextInput({ label, field, ...inputProps }) {  	const { onChange, value, ref } = field; -	console.log(field.name, field.valid, field.value);  	return (  		<div className={`form-field text${field.valid ? "" : " invalid"}`}> @@ -93,13 +92,13 @@ function Checkbox({ label, field, ...inputProps }) {  	);  } -function Select({ label, field, options, ...inputProps }) { +function Select({ label, field, options, children, ...inputProps }) {  	const { onChange, value, ref } = field;  	return (  		<div className="form-field select">  			<label> -				{label} +				{label} {children}  				<select  					{...{ onChange, value, ref }}  					{...inputProps} diff --git a/web/source/settings/lib/form/bool.jsx b/web/source/settings/lib/form/bool.jsx index b124abd50..38364be5c 100644 --- a/web/source/settings/lib/form/bool.jsx +++ b/web/source/settings/lib/form/bool.jsx @@ -20,15 +20,16 @@  const React = require("react"); -module.exports = function useBoolInput({ name, Name }, { defaultValue = false } = {}) { -	const [value, setValue] = React.useState(defaultValue); +const _default = false; +module.exports = function useBoolInput({ name, Name }, { initialValue = _default }) { +	const [value, setValue] = React.useState(initialValue);  	function onChange(e) {  		setValue(e.target.checked);  	}  	function reset() { -		setValue(defaultValue); +		setValue(initialValue);  	}  	// Array / Object hybrid, for easier access in different contexts @@ -45,6 +46,7 @@ module.exports = function useBoolInput({ name, Name }, { defaultValue = false }  		reset,  		value,  		setter: setValue, -		hasChanged: () => value != defaultValue +		hasChanged: () => value != initialValue, +		_default  	});  };
\ No newline at end of file diff --git a/web/source/settings/lib/form/check-list.jsx b/web/source/settings/lib/form/check-list.jsx index b19e17a29..7827671be 100644 --- a/web/source/settings/lib/form/check-list.jsx +++ b/web/source/settings/lib/form/check-list.jsx @@ -81,13 +81,13 @@ const { reducer, actions } = createSlice({  	}  }); -function initialState({ entries, uniqueKey, defaultValue }) { +function initialState({ entries, uniqueKey, initialValue }) {  	const selectedEntries = new Set();  	return {  		entries: syncpipe(entries, [  			(_) => _.map((entry) => {  				let key = entry[uniqueKey]; -				let checked = entry.checked ?? defaultValue; +				let checked = entry.checked ?? initialValue;  				if (checked) {  					selectedEntries.add(key); @@ -110,9 +110,9 @@ function initialState({ entries, uniqueKey, defaultValue }) {  	};  } -module.exports = function useCheckListInput({ name }, { entries, uniqueKey = "key", defaultValue = false }) { +module.exports = function useCheckListInput({ name }, { entries, uniqueKey = "key", initialValue = false }) {  	const [state, dispatch] = React.useReducer(reducer, null, -		() => initialState({ entries, uniqueKey, defaultValue }) // initial state +		() => initialState({ entries, uniqueKey, initialValue }) // initial state  	);  	const toggleAllRef = React.useRef(null); @@ -132,8 +132,8 @@ module.exports = function useCheckListInput({ name }, { entries, uniqueKey = "ke  	}, [state.selectedEntries]);  	const reset = React.useCallback( -		() => dispatch(actions.updateAll(defaultValue)), -		[defaultValue] +		() => dispatch(actions.updateAll(initialValue)), +		[initialValue]  	);  	const onChange = React.useCallback( diff --git a/web/source/settings/lib/form/combo-box.jsx b/web/source/settings/lib/form/combo-box.jsx index 3e8cea44a..ce799f430 100644 --- a/web/source/settings/lib/form/combo-box.jsx +++ b/web/source/settings/lib/form/combo-box.jsx @@ -22,17 +22,18 @@ const React = require("react");  const { useComboboxState } = require("ariakit/combobox"); -module.exports = function useComboBoxInput({ name, Name }, { defaultValue } = {}) { +const _default = ""; +module.exports = function useComboBoxInput({ name, Name }, { initialValue = _default }) {  	const [isNew, setIsNew] = React.useState(false);  	const state = useComboboxState({ -		defaultValue, +		defaultValue: initialValue,  		gutter: 0,  		sameWidth: true  	});  	function reset() { -		state.setValue(""); +		state.setValue(initialValue);  	}  	return Object.assign([ @@ -48,9 +49,11 @@ module.exports = function useComboBoxInput({ name, Name }, { defaultValue } = {}  		name,  		state,  		value: state.value, -		hasChanged: () => state.value != defaultValue, +		setter: (val) => state.setValue(val), +		hasChanged: () => state.value != initialValue,  		isNew,  		setIsNew, -		reset +		reset, +		_default  	});  };
\ No newline at end of file diff --git a/web/source/settings/lib/form/index.js b/web/source/settings/lib/form/index.js index aef3bf0d2..38e426baa 100644 --- a/web/source/settings/lib/form/index.js +++ b/web/source/settings/lib/form/index.js @@ -18,15 +18,52 @@  "use strict"; +const React = require("react"); +const getByDot = require("get-by-dot").default; +  function capitalizeFirst(str) { -	return str.slice(0, 1).toUpperCase() + str.slice(1); +	return str.slice(0, 1).toUpperCase + str.slice(1); +} + +function selectorByKey(key) { +	if (key.includes("[")) { +		// get-by-dot does not support 'nested[deeper][key]' notation, convert to 'nested.deeper.key' +		key = key +			.replace(/\[/g, ".") // nested.deeper].key] +			.replace(/\]/g, ""); // nested.deeper.key +	} + +	return function selector(obj) { +		if (obj == undefined) { +			return undefined; +		} else { +			return getByDot(obj, key); +		} +	};  } -function makeHook(func) { -	return (name, ...args) => func({ -		name, -		Name: capitalizeFirst(name) -	}, ...args); +function makeHook(hookFunction) { +	return function (name, opts = {}) { +		// for dynamically generating attributes like 'setName' +		const Name = React.useMemo(() => capitalizeFirst(name), [name]); + +		const selector = React.useMemo(() => selectorByKey(name), [name]); +		const valueSelector = opts.valueSelector ?? selector; + +		opts.initialValue = React.useMemo(() => { +			if (opts.source == undefined) { +				return opts.defaultValue; +			} else { +				return valueSelector(opts.source) ?? opts.defaultValue; +			} +		}, [opts.source, opts.defaultValue, valueSelector]); + +		const hook = hookFunction({ name, Name }, opts); + +		return Object.assign(hook, { +			name, Name, +		}); +	};  }  module.exports = { diff --git a/web/source/settings/lib/form/radio.jsx b/web/source/settings/lib/form/radio.jsx index 47ab6c726..e95997474 100644 --- a/web/source/settings/lib/form/radio.jsx +++ b/web/source/settings/lib/form/radio.jsx @@ -20,15 +20,16 @@  const React = require("react"); -module.exports = function useRadioInput({ name, Name }, { defaultValue, options } = {}) { -	const [value, setValue] = React.useState(defaultValue); +const _default = ""; +module.exports = function useRadioInput({ name, Name }, { initialValue = _default, options }) { +	const [value, setValue] = React.useState(initialValue);  	function onChange(e) {  		setValue(e.target.value);  	}  	function reset() { -		setValue(defaultValue); +		setValue(initialValue);  	}  	// Array / Object hybrid, for easier access in different contexts @@ -46,6 +47,7 @@ module.exports = function useRadioInput({ name, Name }, { defaultValue, options  		value,  		setter: setValue,  		options, -		hasChanged: () => value != defaultValue +		hasChanged: () => value != initialValue, +		_default  	});  };
\ No newline at end of file diff --git a/web/source/settings/lib/form/submit.js b/web/source/settings/lib/form/submit.js index 6f20165a5..2a81307c5 100644 --- a/web/source/settings/lib/form/submit.js +++ b/web/source/settings/lib/form/submit.js @@ -18,7 +18,6 @@  "use strict"; -const Promise = require("bluebird");  const React = require("react");  const syncpipe = require("syncpipe"); @@ -27,7 +26,7 @@ module.exports = function useFormSubmit(form, mutationQuery, { changedOnly = tru  		throw new ("useFormSubmit: mutationQuery was not an Array. Is a valid useMutation RTK Query provided?");  	}  	const [runMutation, result] = mutationQuery; -	const [usedAction, setUsedAction] = React.useState(); +	const usedAction = React.useRef(null);  	return [  		function submitForm(e) {  			let action; @@ -41,7 +40,7 @@ module.exports = function useFormSubmit(form, mutationQuery, { changedOnly = tru  			if (action == "") {  				action = undefined;  			} -			setUsedAction(action); +			usedAction.current = action;  			// transform the field definitions into an object with just their values   			let updatedFields = [];  			const mutationData = syncpipe(form, [ @@ -65,19 +64,11 @@ module.exports = function useFormSubmit(form, mutationQuery, { changedOnly = tru  			mutationData.action = action; -			return Promise.try(() => { -				return runMutation(mutationData); -			}).then((res) => { -				if (res.error == undefined) { -					updatedFields.forEach((field) => { -						field.reset(); -					}); -				} -			}); +			return runMutation(mutationData);  		},  		{  			...result, -			action: usedAction +			action: usedAction.current  		}  	];  };
\ No newline at end of file diff --git a/web/source/settings/lib/form/text.jsx b/web/source/settings/lib/form/text.jsx index d9a9ab28c..ce116f9ab 100644 --- a/web/source/settings/lib/form/text.jsx +++ b/web/source/settings/lib/form/text.jsx @@ -20,15 +20,16 @@  const React = require("react"); +const _default = "";  module.exports = function useTextInput({ name, Name }, { -	defaultValue = "", +	initialValue = _default,  	dontReset = false,  	validator,  	showValidation = true,  	initValidation  } = {}) { -	const [text, setText] = React.useState(defaultValue); +	const [text, setText] = React.useState(initialValue);  	const textRef = React.useRef(null);  	const [validation, setValidation] = React.useState(initValidation ?? ""); @@ -48,7 +49,7 @@ module.exports = function useTextInput({ name, Name }, {  	function reset() {  		if (!dontReset) { -			setText(defaultValue); +			setText(initialValue);  		}  	} @@ -81,6 +82,7 @@ module.exports = function useTextInput({ name, Name }, {  		setter: setText,  		valid,  		validate: () => setValidation(validator(text)), -		hasChanged: () => text != defaultValue +		hasChanged: () => text != initialValue, +		_default  	});  };
\ No newline at end of file diff --git a/web/source/settings/user/profile.js b/web/source/settings/user/profile.js index 76f416dd1..b2d2d25b3 100644 --- a/web/source/settings/user/profile.js +++ b/web/source/settings/user/profile.js @@ -71,12 +71,12 @@ function UserProfileForm({ data: profile }) {  	const form = {  		avatar: useFileInput("avatar", { withPreview: true }),  		header: useFileInput("header", { withPreview: true }), -		displayName: useTextInput("display_name", { defaultValue: profile.display_name }), -		note: useTextInput("note", { defaultValue: profile.source?.note }), -		customCSS: useTextInput("custom_css", { defaultValue: profile.custom_css }), -		bot: useBoolInput("bot", { defaultValue: profile.bot }), -		locked: useBoolInput("locked", { defaultValue: profile.locked }), -		enableRSS: useBoolInput("enable_rss", { defaultValue: profile.enable_rss }), +		displayName: useTextInput("display_name", { source: profile }), +		note: useTextInput("note", { source: profile, valueSelector: (p) => p.source?.note }), +		customCSS: useTextInput("custom_css", { source: profile }), +		bot: useBoolInput("bot", { source: profile }), +		locked: useBoolInput("locked", { source: profile }), +		enableRSS: useBoolInput("enable_rss", { source: profile }),  	};  	const [submitForm, result] = useFormSubmit(form, query.useUpdateCredentialsMutation()); diff --git a/web/source/settings/user/settings.js b/web/source/settings/user/settings.js index df258d39c..6b6b3c09f 100644 --- a/web/source/settings/user/settings.js +++ b/web/source/settings/user/settings.js @@ -49,7 +49,6 @@ module.exports = function UserSettings() {  };  function UserSettingsForm({ data }) { -	const { source } = data;  	/* form keys  		- string source[privacy]  		- bool source[sensitive] @@ -58,10 +57,10 @@ function UserSettingsForm({ data }) {  	 */  	const form = { -		defaultPrivacy: useTextInput("source[privacy]", { defaultValue: source.privacy ?? "unlisted" }), -		isSensitive: useBoolInput("source[sensitive]", { defaultValue: source.sensitive }), -		language: useTextInput("source[language]", { defaultValue: source.language?.toUpperCase() ?? "EN" }), -		format: useTextInput("source[status_format]", { defaultValue: source.status_format ?? "plain" }), +		defaultPrivacy: useTextInput("source[privacy]", { source: data, defaultValue: "unlisted" }), +		isSensitive: useBoolInput("source[sensitive]", { source: data }), +		language: useTextInput("source[language]", { source: data, valueSelector: (s) => s.source.language?.toUpperCase() ?? "EN" }), +		format: useTextInput("source[status_format]", { source: data, defaultValue: "plain" }),  	};  	const [submitForm, result] = useFormSubmit(form, query.useUpdateCredentialsMutation()); @@ -132,9 +131,24 @@ function PasswordChange() {  	return (  		<form className="change-password" onSubmit={submitForm}>  			<h1>Change password</h1> -			<TextInput type="password" field={form.oldPassword} label="Current password" /> -			<TextInput type="password" field={form.newPassword} label="New password" /> -			<TextInput type="password" field={verifyNewPassword} label="Confirm new password" /> +			<TextInput +				type="password" +				name="password" +				field={form.oldPassword} +				label="Current password" +			/> +			<TextInput +				type="password" +				name="newPassword" +				field={form.newPassword} +				label="New password" +			/> +			<TextInput +				type="password" +				name="confirmNewPassword" +				field={verifyNewPassword} +				label="Confirm new password" +			/>  			<MutationButton label="Change password" result={result} />  		</form>  	); diff --git a/web/source/yarn.lock b/web/source/yarn.lock index 276a74362..25bc0b0c4 100644 --- a/web/source/yarn.lock +++ b/web/source/yarn.lock @@ -3091,6 +3091,11 @@ get-assigned-identifiers@^1.1.0, get-assigned-identifiers@^1.2.0:    resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1"    integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ== +get-by-dot@^1.0.2: +  version "1.0.2" +  resolved "https://registry.yarnpkg.com/get-by-dot/-/get-by-dot-1.0.2.tgz#8ba0ef82fe3435ce57faa133e45357a9059a7081" +  integrity sha512-gzOcBY84Hd7vTE5r5pXHSyPGuFAxABCfYV3Oey8Z6RxikkhJbbL9x3vu0cOn53QjZfQI1X5JZuNCVwOlvqLBwQ== +  get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3:    version "1.1.3"    resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" | 
