diff --git a/libs/remix-ui/publish-to-storage/src/lib/publishOnSwarm.tsx b/libs/remix-ui/publish-to-storage/src/lib/publishOnSwarm.tsx index a98e8375fa..627577e3ad 100644 --- a/libs/remix-ui/publish-to-storage/src/lib/publishOnSwarm.tsx +++ b/libs/remix-ui/publish-to-storage/src/lib/publishOnSwarm.tsx @@ -2,12 +2,12 @@ import { Bee } from '@ethersphere/bee-js' // eslint-disable-next-line no-unused-vars import type { UploadResult } from '@ethersphere/bee-js' -const beeNodes = [ - new Bee('http://localhost:1633/'), - new Bee('https://bee-0.gateway.ethswarm.org/') -] +// public gateway node address +// TODO should change to https://api.ethswarm.org/ +const publicBeeNode = new Bee('https://bee-9.gateway.ethswarm.org/') -const postageBatchId = 'b75edc084f30f76368a6a1a596c39d3d913048d20b34d00a69ddd14cb15f507f' +// on the public gateway the postage stamp id is not relevant, so we use all zeroes +const defaultPostageStampId = '0000000000000000000000000000000000000000000000000000000000000000' export const publishToSwarm = async (contract, api) => { // gather list of files to publish @@ -55,11 +55,24 @@ export const publishToSwarm = async (contract, api) => { console.log(error) }) })) - // publish the list of sources in order, fail if any failed + // the list of nodes to publish to + const beeNodes = [ + publicBeeNode + ] + + // add custom private Bee node to the list + const postageStampId = api.config.get('settings/swarm-postage-stamp-id') || defaultPostageStampId + const privateBeeAddress = api.config.get('settings/swarm-private-bee-address') + if (privateBeeAddress) { + const privateBee = new Bee(privateBeeAddress) + beeNodes.push(privateBee) + } + + // publish the list of sources in order, fail if any failed await Promise.all(sources.map(async (item) => { try { - const result = await swarmVerifiedPublish(item.content, item.hash) + const result = await swarmVerifiedPublish(beeNodes, postageStampId, item.content, item.hash) try { item.hash = result.url.match('bzz-raw://(.+)')[1] @@ -78,7 +91,7 @@ export const publishToSwarm = async (contract, api) => { const metadataContent = JSON.stringify(metadata) try { - const result = await swarmVerifiedPublish(metadataContent, '') + const result = await swarmVerifiedPublish(beeNodes, postageStampId, metadataContent, '') try { contract.metadataHash = result.url.match('bzz-raw://(.+)')[1] @@ -101,9 +114,9 @@ export const publishToSwarm = async (contract, api) => { return { uploaded, item } } -const swarmVerifiedPublish = async (content, expectedHash): Promise> => { +const swarmVerifiedPublish = async (beeNodes: Bee[], postageStampId: string, content, expectedHash): Promise> => { try { - const results = await uploadToBeeNodes(content) + const results = await uploadToBeeNodes(beeNodes, postageStampId, content) const hash = hashFromResults(results) if (expectedHash && hash !== expectedHash) { @@ -125,14 +138,15 @@ const hashFromResults = (results: UploadResult[]) => { throw new Error('no result') } -const uploadToBee = async (bee, content) => { +const uploadToBee = async (bee: Bee, postageStampId: string, content) => { try { - return await bee.uploadData(postageBatchId, content) + return await bee.uploadData(postageStampId, content) } catch { + // ignore errors for now return null } } -const uploadToBeeNodes = (content) => { - return Promise.all(beeNodes.map((node) => uploadToBee(node, content))) +const uploadToBeeNodes = (beeNodes: Bee[], postageBatchId: string, content) => { + return Promise.all(beeNodes.map(node => uploadToBee(node, postageBatchId, content))) } diff --git a/libs/remix-ui/settings/src/lib/constants.ts b/libs/remix-ui/settings/src/lib/constants.ts index f26d43aff8..0da1f23863 100644 --- a/libs/remix-ui/settings/src/lib/constants.ts +++ b/libs/remix-ui/settings/src/lib/constants.ts @@ -10,3 +10,5 @@ export const ethereunVMText = 'Always use Javascript VM at load' export const wordWrapText = 'Word wrap in editor' export const enablePersonalModeText = ' Enable Personal Mode for web3 provider. Transaction sent over Web3 will use the web3.personal API.\n' export const matomoAnalytics = 'Enable Matomo Analytics. We do not collect personally identifiable information (PII). The info is used to improve the site’s UX & UI. See more about ' +export const swarmSettingsTitle = 'Swarm Settings' +export const swarmSettingsText = 'Swarm Settings' diff --git a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx index 336fef5c0f..e027a54b8f 100644 --- a/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx +++ b/libs/remix-ui/settings/src/lib/remix-ui-settings.tsx @@ -1,10 +1,10 @@ import React, { useState, useReducer, useEffect, useCallback } from 'react' // eslint-disable-line import { CopyToClipboard } from '@remix-ui/clipboard' // eslint-disable-line -import { enablePersonalModeText, ethereunVMText, generateContractMetadataText, gitAccessTokenLink, gitAccessTokenText, gitAccessTokenText2, gitAccessTokenTitle, matomoAnalytics, textDark, textSecondary, warnText, wordWrapText } from './constants' +import { enablePersonalModeText, ethereunVMText, generateContractMetadataText, gitAccessTokenLink, gitAccessTokenText, gitAccessTokenText2, gitAccessTokenTitle, matomoAnalytics, swarmSettingsTitle, textDark, textSecondary, warnText, wordWrapText } from './constants' import './remix-ui-settings.css' -import { ethereumVM, generateContractMetadat, personal, textWrapEventAction, useMatomoAnalytics, saveTokenToast, removeTokenToast } from './settingsAction' +import { ethereumVM, generateContractMetadat, personal, textWrapEventAction, useMatomoAnalytics, saveTokenToast, removeTokenToast, saveSwarmSettingsToast } from './settingsAction' import { initialState, toastInitialState, toastReducer, settingReducer } from './settingsReducer' import { Toaster } from '@remix-ui/toaster'// eslint-disable-line import { RemixUiThemeModule, ThemeModule} from '@remix-ui/theme-module' @@ -22,6 +22,9 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { const [, dispatch] = useReducer(settingReducer, initialState) const [state, dispatchToast] = useReducer(toastReducer, toastInitialState) const [tokenValue, setTokenValue] = useState('') + const [themeName, setThemeName] = useState('') + const [privateBeeAddress, setPrivateBeeAddress] = useState('') + const [postageStampId, setPostageStampId] = useState('') useEffect(() => { const token = props.config.get('settings/gist-access-token') @@ -32,7 +35,15 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { if (token) { setTokenValue(token) } - }, [state.message]) + const configPrivateBeeAddress = props.config.get('settings/swarm-private-bee-address') + if (configPrivateBeeAddress) { + setPrivateBeeAddress(configPrivateBeeAddress) + } + const configPostageStampId = props.config.get('settings/swarm-postage-stamp-id') + if (configPostageStampId) { + setPostageStampId(configPostageStampId) + } + }, [themeName, state.message]) useEffect(() => { if (props.useMatomoAnalytics !== null) useMatomoAnalytics(props.config, props.useMatomoAnalytics, dispatch) @@ -150,12 +161,76 @@ export const RemixUiSettings = (props: RemixUiSettingsProps) => { ) + const handleSavePrivateBeeAddress = useCallback( + (event) => { + setPrivateBeeAddress(event.target.value) + }, + [privateBeeAddress] + ) + + const handleSavePostageStampId = useCallback( + (event) => { + setPostageStampId(event.target.value) + }, + [postageStampId] + ) + + const saveSwarmSettings = () => { + saveSwarmSettingsToast(props.config, dispatchToast, privateBeeAddress, postageStampId) + } + + const swarmSettings = () => ( +
+
+
{ swarmSettingsTitle }
+
+
+ +
+
+
+
+ +
+
+
+
+
+ saveSwarmSettings()} value="Save" type="button" disabled={privateBeeAddress === ''}> +
+
+
+ + ) + + const themes = () => { + const themes = props._deps.themeModule.getThemes() + if (themes) { + return themes.map((aTheme, index) => ( +
+ { onswitchTheme(event, aTheme.name) }} className="align-middle custom-control-input" name='theme' id={aTheme.name} data-id={`settingsTabTheme${aTheme.name}`} checked = {props._deps.themeModule.active === aTheme.name }/> + +
+ ) + ) + } + } + return (
{state.message ? : null} {generalConfig()} {gistToken()} + {swarmSettings()} +
+
+
Themes
+
+ {themes()} +
+
+
) } diff --git a/libs/remix-ui/settings/src/lib/settingsAction.ts b/libs/remix-ui/settings/src/lib/settingsAction.ts index 846a6511b5..48f9572040 100644 --- a/libs/remix-ui/settings/src/lib/settingsAction.ts +++ b/libs/remix-ui/settings/src/lib/settingsAction.ts @@ -50,3 +50,9 @@ export const removeTokenToast = (config, dispatch) => { config.set('settings/gist-access-token', '') dispatch({ type: 'removed', payload: { message: 'Access token removed' } }) } + +export const saveSwarmSettingsToast = (config, dispatch, privateBeeAddress, postageStampId) => { + config.set('settings/swarm-private-bee-address', privateBeeAddress) + config.set('settings/swarm-postage-stamp-id', postageStampId) + dispatch({ type: 'save', payload: { message: 'Swarm settings have been saved' } }) +}