diff --git a/app/ts/components/pages/WebsiteAccess.tsx b/app/ts/components/pages/WebsiteAccess.tsx index 955d205a..ae58e49b 100644 --- a/app/ts/components/pages/WebsiteAccess.tsx +++ b/app/ts/components/pages/WebsiteAccess.tsx @@ -11,6 +11,7 @@ import { sendPopupMessageToBackgroundPage } from '../../background/backgroundUti import { InterceptorDisabledIcon, RequestBlockedIcon, SearchIcon, TrashIcon } from '../subcomponents/icons.js' import { BigAddress, SmallAddress } from '../subcomponents/address.js' import { createPortal } from 'preact/compat' +import { useOptionalComputed } from '../../utils/OptionalSignal.js' const URL_HASH_KEY = 'origin' const URL_HASH_PREFIX = `#${ URL_HASH_KEY }:` @@ -18,7 +19,7 @@ const URL_HASH_PREFIX = `#${ URL_HASH_KEY }:` type WebsiteAccessContext = { searchQuery: Signal websiteAccessList: Signal - addressAccessMetadata: Signal + addressAccessMetadata: Signal selectedDomain: Signal } @@ -27,7 +28,7 @@ const WebsiteAccessContext = createContext(und const WebsiteAccessProvider = ({ children }: { children: ComponentChildren }) => { const websiteAccessList = useSignal([]) const searchQuery = useSignal('') - const addressAccessMetadata = useSignal(undefined) + const addressAccessMetadata = useSignal([]) const selectedDomain = useSignal(undefined) const retrieveWebsiteAccess = (filter?: RetrieveWebsiteAccessFilter) => { @@ -71,9 +72,7 @@ const WebsiteAccessProvider = ({ children }: { children: ComponentChildren }) => // initially set selectedDomain when the page loads/reloads handleHashChange() window.addEventListener('hashchange', handleHashChange) - return () => { - window.removeEventListener('hashchange', handleHashChange) - } + return () => window.removeEventListener('hashchange', handleHashChange) } useSignalEffect(updateListOnSearch) @@ -166,33 +165,13 @@ const SearchForm = (props: SearchFormProps) => { const WebsiteSettingsList = () => { const { websiteAccessList } = useWebsiteAccess() - const updateSelection = (event: Event) => { - event.preventDefault() - const formElement = event.currentTarget - if (!(event instanceof SubmitEvent) || !(formElement instanceof HTMLFormElement)) return - - const formData = new FormData(formElement) - const selectedWebsiteOrigin = formData.get(URL_HASH_KEY)?.toString() - - if (!selectedWebsiteOrigin) { - window.location.href = window.location.pathname - return - } - - window.location.href = `${ window.location.pathname }${ URL_HASH_PREFIX }${ selectedWebsiteOrigin }` - } - return (

Websites

-
- { websiteAccessList.value.length < 1 ? : ( - <> -
    { websiteAccessList.value.map((access, index) => ) }
- - - )} - + { websiteAccessList.value.length < 1 ? : <> +
    { websiteAccessList.value.map((access, index) => ) }
+ + }
) } @@ -214,9 +193,8 @@ type WebsiteAccessOverviewProps = { } const WebsiteAccessOverview = ({ websiteAccess, checked }: WebsiteAccessOverviewProps) => { - const handleChange = (event: Event) => { - if (!(event.currentTarget instanceof HTMLLabelElement) || !event.currentTarget.form) return - event.currentTarget.form.requestSubmit() + const handleChange = () => { + window.location.href = `${ window.location.pathname }${ URL_HASH_PREFIX }${ websiteAccess.website.websiteOrigin }` } const getWebsiteStatus = () => { @@ -262,12 +240,11 @@ const FullFrameWindow = ({ children }: { children: ComponentChildren }) => { const WebsiteSettingsDetail = () => { const { websiteAccessList, selectedDomain } = useWebsiteAccess() - - const selectedWebsiteAccess = useComputed(() => websiteAccessList.value.find(access => access.website.websiteOrigin === selectedDomain.value)) + const selectedWebsiteAccess = useOptionalComputed(() => websiteAccessList.value.find(access => access.website.websiteOrigin === selectedDomain.value)) const closeDetails = () => { window.location.hash = '' } - if (!selectedWebsiteAccess.value) return <> + if (selectedWebsiteAccess.value === undefined) return <> return ( @@ -277,30 +254,33 @@ const WebsiteSettingsDetail = () => {
- - - + + +
) } -const DetailsHeader = ({ websiteAccess }: { websiteAccess: WebsiteAccess | undefined }) => { - if (!websiteAccess) return <> - return ( -
-
-
-

{ websiteAccess.website.title }

-

‎{ websiteAccess.website.websiteOrigin }

-
-
- ) +const DetailsHeader = ({ websiteAccess }: { websiteAccess: Signal }) => { + return ( +
+
+
+

{ websiteAccess.value.website.title }

+

‎{ websiteAccess.value.website.websiteOrigin }

+
+
+ ) } -const NoAccessPrompt = ({ websiteAccess }: { websiteAccess: Signal }) => { +const NoAccessPrompt = ({ websiteAccess }: { websiteAccess: Signal }) => { const { selectedDomain } = useWebsiteAccess() + const website = useComputed(() => websiteAccess.value.website) + + // If the website has been granted access, don't show this message + if (websiteAccess.value.access === true) return <> const confirmOrRejectRemoval = async (returnValue: string) => { if (returnValue !== 'confirm' || !websiteAccess.value) return @@ -308,18 +288,16 @@ const NoAccessPrompt = ({ websiteAccess }: { websiteAccess: Signal - return (

This website was denied access to The Interceptor.

-

Interceptor will automatically deny further requests from for access while this preference is set.

+

Interceptor will automatically deny further requests from for access while this preference is set.

Stop automatically denying access requests

Stop automatically denying access requests

-

After confirming this action, The Interceptor will stop automatically denying access requests from and will prompt you for permission the next time you try to connect.

+

After confirming this action, The Interceptor will stop automatically denying access requests from and will prompt you for permission the next time you try to connect.

Cancel Confirm @@ -330,27 +308,28 @@ const NoAccessPrompt = ({ websiteAccess }: { websiteAccess: Signal }) => { +const AddressAccessList = ({ websiteAccess }: { websiteAccess: Signal }) => { const access = websiteAccess.value + const website = useComputed(() => websiteAccess.value.website) - if (!access || access.addressAccess === undefined || access.addressAccess.length < 1) return <> + if (!access || access.addressAccess === undefined || access.addressAccess.length < 1 || website === undefined) return <> return (

Configure website access to these address(es).

- { access.addressAccess.map(addressAcces => ) } + { access.addressAccess.map(addressAcces => ) }
) } -const AddressAccessCard = ({ website, addressAccess }: { website: Website, addressAccess: WebsiteAddressAccess }) => { +const AddressAccessCard = ({ website, addressAccess }: { website: Signal, addressAccess: WebsiteAddressAccess }) => { const { addressAccessMetadata } = useWebsiteAccess() const setAddressAccess = (event: Event) => { if (!(event.target instanceof HTMLInputElement)) return - sendPopupMessageToBackgroundPage({ method: 'popup_allowOrPreventAddressAccessForWebsite', data: { website, address: addressAccess.address, allowAccess: event.target.checked } }) + sendPopupMessageToBackgroundPage({ method: 'popup_allowOrPreventAddressAccessForWebsite', data: { website: website.value, address: addressAccess.address, allowAccess: event.target.checked } }) } const renameAddressCallBack = (newAddress: AddressBookEntry) => { @@ -358,21 +337,22 @@ const AddressAccessCard = ({ website, addressAccess }: { website: Website, addre // TODO: Implement address editing https://github.com/DarkFlorist/TheInterceptor/issues/1131 } - const addressBookEntry = useComputed(() => addressAccessMetadata.value?.find(entry => entry.address === addressAccess.address)) + const addressBookEntry = useOptionalComputed(() => addressAccessMetadata.value.find(entry => entry.address === addressAccess.address)) + if (addressBookEntry.deepValue === undefined) return <> return (
- - + +
) } -const RemoveAddressConfirmation = ({ website, addressBookEntry }: { addressBookEntry: AddressBookEntry | undefined, website: Website }) => { +const RemoveAddressConfirmation = ({ website, addressBookEntry }: { addressBookEntry: AddressBookEntry, website: Signal }) => { const removeAddressAccessForWebsite = async () => { if (!addressBookEntry) return - sendPopupMessageToBackgroundPage({ method: 'popup_removeWebsiteAddressAccess', data: { websiteOrigin: website.websiteOrigin, address: addressBookEntry.address } }) + sendPopupMessageToBackgroundPage({ method: 'popup_removeWebsiteAddressAccess', data: { websiteOrigin: website.value.websiteOrigin, address: addressBookEntry.address } }) } const confirmOrRejectRemoval = (returnValue: 'confirm' | 'reject') => { @@ -380,8 +360,6 @@ const RemoveAddressConfirmation = ({ website, addressBookEntry }: { addressBookE removeAddressAccessForWebsite() } - if (!addressBookEntry) return <> - return ( @@ -400,9 +378,7 @@ const RemoveAddressConfirmation = ({ website, addressBookEntry }: { addressBookE ) } -const AdvancedSettings = ({ websiteAccess }: { websiteAccess: Signal }) => { - if (!websiteAccess.value || !websiteAccess.value.access) return <> - +const AdvancedSettings = ({ websiteAccess }: { websiteAccess: Signal }) => { return ( @@ -412,15 +388,14 @@ const AdvancedSettings = ({ websiteAccess }: { websiteAccess: Signal }) => { +const BlockRequestSetting = ({ websiteAccess }: { websiteAccess: Signal }) => { const setWebsiteExternalRequestBlocking = async (shouldBlock: boolean) => { if (!websiteAccess.value) return sendPopupMessageToBackgroundPage({ method: 'popup_blockOrAllowExternalRequests', data: { website: websiteAccess.value.website, shouldBlock } }) } - if (!websiteAccess.value) return <> - - const requestBlockMode = useComputed(() => websiteAccess.value?.declarativeNetRequestBlockMode) + const requestBlockMode = useComputed(() => websiteAccess.value.declarativeNetRequestBlockMode) + const website = useComputed(() => websiteAccess.value.website) const confirmOrRejectRequestBlocking = (response: 'confirm' | 'reject') => { if (response !== 'confirm') return @@ -444,7 +419,7 @@ const BlockRequestSetting = ({ websiteAccess }: { websiteAccess: Signal

Confirm Blocking External Requests

-

This will prevent from requesting resources outside its domain, which can lead to erratic behavior or even cause it to stop functioning entirely.

+

This will prevent from requesting resources outside its domain, which can lead to erratic behavior or even cause it to stop functioning entirely.

Are you sure you want to block external requests from this website?

Cancel @@ -460,7 +435,7 @@ const BlockRequestSetting = ({ websiteAccess }: { websiteAccess: Signal }) => { +const DisableProtectionSetting = ({ websiteAccess }: { websiteAccess: Signal }) => { const disableWebsiteProtection = async (shouldDisable: boolean = true) => { if (!websiteAccess.value) return @@ -472,8 +447,8 @@ const DisableProtectionSetting = ({ websiteAccess }: { websiteAccess: Signal - const isInterceptorDisabled = useComputed(() => Boolean(websiteAccess.value?.interceptorDisabled)) + const isInterceptorDisabled = useComputed(() => Boolean(websiteAccess.value.interceptorDisabled)) + const website = useComputed(() => websiteAccess.value.website) return (
@@ -492,7 +467,7 @@ const DisableProtectionSetting = ({ websiteAccess }: { websiteAccess: Signal

Disable Interceptor Protection

-

Interceptor will no longer be able to simulate transactions from , which could potentially lead to loss of assets. Please exercise caution.

+

Interceptor will no longer be able to simulate transactions from , which could potentially lead to loss of assets. Please exercise caution.

Are you sure you want to disable protection for this website?

Cancel @@ -507,8 +482,9 @@ const DisableProtectionSetting = ({ websiteAccess }: { websiteAccess: Signal }) => { +const RemoveWebsiteSetting = ({ websiteAccess }: { websiteAccess: Signal }) => { const { selectedDomain } = useWebsiteAccess() + const website = useComputed(() => websiteAccess.value.website) const confirmOrRejectUpdate = async (response: 'confirm' | 'reject') => { if (response !== 'confirm' || !websiteAccess.value) return @@ -516,8 +492,6 @@ const RemoveWebsiteSetting = ({ websiteAccess }: { websiteAccess: Signal - return (
@@ -532,7 +506,7 @@ const RemoveWebsiteSetting = ({ websiteAccess }: { websiteAccess: Signal

Confirm Website Removal

-

You are about to remove from the list of allowed sites. By doing so, the website will no longer have access to your wallet addresses.

+

You are about to remove from the list of allowed sites. By doing so, the website will no longer have access to your wallet addresses.

Are you sure you want to remove this website?

Cancel @@ -546,11 +520,11 @@ const RemoveWebsiteSetting = ({ websiteAccess }: { websiteAccess: Signal { +const WebsiteCard = ({ website }: { website: Signal }) => { return (
- -
{ website.websiteOrigin }
+ +
{ website.value.websiteOrigin }
) } diff --git a/app/ts/utils/OptionalSignal.ts b/app/ts/utils/OptionalSignal.ts index 58d39164..49155a4f 100644 --- a/app/ts/utils/OptionalSignal.ts +++ b/app/ts/utils/OptionalSignal.ts @@ -1,4 +1,4 @@ -import { ReadonlySignal, Signal, batch } from '@preact/signals' +import { ReadonlySignal, Signal, batch, useSignalEffect } from '@preact/signals' import { useMemo } from 'preact/hooks' export class OptionalSignal extends Signal | undefined> implements ReadonlySignal | undefined> { @@ -43,3 +43,9 @@ export class OptionalSignal extends Signal | undefined> implements export function useOptionalSignal(value: Signal | T | undefined, startUndefined?: boolean) { return useMemo(() => new OptionalSignal(value, startUndefined), []) } + +export const useOptionalComputed = (computeFn: () => T | undefined) => { + const resultSignal = useOptionalSignal(undefined) + useSignalEffect(() => { resultSignal.deepValue = computeFn() }) + return resultSignal +}