Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop relying exclusively on Infura for IPFS #200

Merged
merged 8 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/dev-cd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ env:
REACT_APP_SUBGRAPH_OPTIMISM: auryn-macmillan/tabula-optimism
REACT_APP_SUBGRAPH_OPTIMISM_ON_GNOSIS_CHAIN: auryn-macmillan/tabula-optimism-on-gnosis-chain
REACT_APP_IPFS_GATEWAY: https://ipfs.io/ipfs
REACT_APP_IPFS_INFURA_PROJECT_ID: ${{ secrets.REACT_APP_IPFS_INFURA_PROJECT_ID }}
REACT_APP_IPFS_INFURA_SECRET_KEY: ${{ secrets.REACT_APP_IPFS_INFURA_SECRET_KEY }}
jobs:
deploy:
runs-on: ubuntu-latest
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/prod-release-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ env:
REACT_APP_SUBGRAPH_OPTIMISM: auryn-macmillan/tabula-optimism
REACT_APP_SUBGRAPH_OPTIMISM_ON_GNOSIS_CHAIN: auryn-macmillan/tabula-optimism-on-gnosis-chain
REACT_APP_IPFS_GATEWAY: https://ipfs.io/ipfs
REACT_APP_IPFS_INFURA_PROJECT_ID: ${{ secrets.REACT_APP_IPFS_INFURA_PROJECT_ID }}
REACT_APP_IPFS_INFURA_SECRET_KEY: ${{ secrets.REACT_APP_IPFS_INFURA_SECRET_KEY }}
jobs:
deploy:
runs-on: ubuntu-latest
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ packages/subgraph/build
packages/subgraph/generated
packages/subgraph/tests/.bin
packages/subgraph/subgraph.yaml
packages/subgraph/.env
**/.env
.vscode/*
2 changes: 0 additions & 2 deletions packages/app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@ REACT_APP_SUBGRAPH_POLYGON=auryn-macmillan/tabula-polygon
REACT_APP_SUBGRAPH_ARBITRUM=auryn-macmillan/tabula-arbitrum
REACT_APP_SUBGRAPH_OPTIMISM=auryn-macmillan/tabula-optimism
REACT_APP_IPFS_GATEWAY=https://ipfs.io/ipfs
REACT_APP_IPFS_INFURA_PROJECT_ID=
REACT_APP_IPFS_INFURA_SECRET_KEY=
REACT_APP_SUBGRAPH_OPTIMISM_ON_GNOSIS_CHAIN=auryn-macmillan/tabula-optimism-on-gnosis-chain
1 change: 1 addition & 0 deletions packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"ethers": "^5.6.1",
"gh-pages": "^3.2.3",
"graphql": "^16.3.0",
"ipfs-core": "0.14.3",
"ipfs-http-client": "54.0.0",
"is-ipfs": "^6.0.2",
"lodash": "^4.17.21",
Expand Down
139 changes: 139 additions & 0 deletions packages/app/src/components/commons/IPFSNodeModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/* eslint-disable react-hooks/exhaustive-deps */
import { Button, Divider, Grid, Modal, ModalProps, styled, TextField, Typography } from "@mui/material"
import React, { useEffect, useRef, useState } from "react"

import { palette, typography } from "../../theme"
import { ViewContainer } from "./ViewContainer"
import CloseIcon from "@mui/icons-material/Close"
import useLocalStorage from "../../hooks/useLocalStorage"
import { useNotification } from "../../hooks/useNotification"

const ModalContainer = styled(ViewContainer)({
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
borderRadius: 8,
width: 648,
background: palette.whites[1000],
padding: 24,
})

export interface IPFSNodeModalProps extends Omit<ModalProps, "children"> {}

const IPFSNodeModal: React.FC<IPFSNodeModalProps> = (props) => {
const ref = useRef(null)
const [ipfsNodeEndpoint, setIpfsNodeEndpoint] = useLocalStorage<string | undefined>("ipfsNodeEndpoint", undefined)
const [endpoint, setEndpoint] = useState<string>("")
const openNotification = useNotification()
useEffect(() => {
if (ipfsNodeEndpoint && !endpoint) {
setEndpoint(ipfsNodeEndpoint)
}
}, [])

const handleIpfsNode = () => {
setIpfsNodeEndpoint(endpoint !== "" ? endpoint : undefined)
if (props.onClose) {
props.onClose({}, "backdropClick")
}
openNotification({
message: "IPFS node endpoint successfully updated",
autoHideDuration: 5000,
variant: "success",
preventDuplicate: true,
})
}

return (
<Modal open={props.open} onClose={props.onClose}>
<ModalContainer maxWidth="md" ref={ref}>
<Grid container spacing={3} py={3} px={4} flexDirection="column">
<Grid item>
<Grid container justifyContent="space-between" alignItems="center">
<Grid item>
<Typography
fontFamily={typography.fontFamilies.sans}
variant="h5"
sx={{ margin: 0 }}
color={palette.grays[1000]}
>
Update IPFS Node
</Typography>
</Grid>
<Grid item>
<CloseIcon
style={{ cursor: "pointer" }}
onClick={() => {
props.onClose && props.onClose({}, "escapeKeyDown")
}}
/>
</Grid>
</Grid>
</Grid>

<Grid item>
<Grid container gap={1}>
<Typography fontFamily={typography.fontFamilies.sans}>
Tabula will automatically connect to your locale IPFS node if you have a node running at the default
endpoint:
</Typography>
<Typography fontWeight={700} fontFamily={typography.fontFamilies.monospace} color={palette.grays[800]}>
http://localhost:5001/api/v0
</Typography>
</Grid>
</Grid>

<Grid item>
<Typography fontFamily={typography.fontFamilies.sans}>
If you want to connect to an IPFS node running at a different URL, you can specify this below.
</Typography>
</Grid>

<Grid item>
<Grid container spacing={3} flexDirection={"row"} alignItems="center">
<Grid item md={4}>
<Typography
fontFamily={typography.fontFamilies.sans}
variant="h6"
fontSize={16}
sx={{ margin: 0 }}
color={palette.grays[1000]}
>
IPFS Node endpoint
</Typography>
</Grid>
<Grid item md={8}>
<TextField
placeholder="http://localhost:5001/api/v0"
fullWidth
value={endpoint}
onChange={(event) => setEndpoint(event.target.value)}
/>
</Grid>
</Grid>
</Grid>
<Grid item>
<Typography fontFamily={typography.fontFamilies.sans} sx={{ fontStyle: "italic" }}>
If Tablua cannot connect to a running IPFS node, it will spin up an IPFS node in the browser.
</Typography>
</Grid>

<Grid item>
<Divider />
</Grid>

<Grid item>
<Grid container justifyContent="flex-end">
<Button variant="contained" onClick={handleIpfsNode}>
Update IPFS Node
</Button>
</Grid>
</Grid>
</Grid>
</ModalContainer>
</Modal>
)
}

export default IPFSNodeModal
2 changes: 1 addition & 1 deletion packages/app/src/components/commons/PublicationAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const PublicationAvatar: React.FC<PublicationAvatarProps> = ({ defaultImage, onF
setDefaultImageSrc(src)
}
}
if (ipfs.isReady && defaultImage != null && defaultImageSrc === "") {
if (defaultImage != null && defaultImageSrc === "") {
getDefaultImageSrc()
}
}, [defaultImage, ipfs, defaultImageSrc])
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/components/commons/UploadFile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const UploadFile: React.FC<UploadFileProps> = ({ defaultImage, onFileSele
setDefaultImageSrc(src)
}
}
if (ipfs.isReady && defaultImage != null && defaultImageSrc === "") {
if (defaultImage != null && defaultImageSrc === "") {
getDefaultImageSrc()
}
}, [defaultImage, ipfs, defaultImageSrc])
Expand Down
18 changes: 17 additions & 1 deletion packages/app/src/components/commons/UserOptions.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { Avatar, Grid, Paper, styled, Typography } from "@mui/material"
import React from "react"
import React, { useState } from "react"
import { palette } from "../../theme"
import PushPinIcon from "@mui/icons-material/PushPin"
import LinkOffIcon from "@mui/icons-material/LinkOff"
import ExitToAppIcon from "@mui/icons-material/ExitToApp"

import ShortcutIcon from "@mui/icons-material/Shortcut"
import { useWeb3React } from "@web3-react/core"
import { useLocation, useNavigate } from "react-router-dom"
import { usePublicationContext } from "../../services/publications/contexts"
import useLocalStorage from "../../hooks/useLocalStorage"
import IPFSNodeModal from "./IPFSNodeModal"

const UserOptionsContainer = styled(Paper)({
padding: 8,
Expand All @@ -28,9 +31,11 @@ const MenuItem = styled(Grid)({
export const UserOptions: React.FC = () => {
const { deactivate } = useWeb3React()
const { setCurrentPath } = usePublicationContext()
const [showIPFSModal, setShowIPFSModal] = useState<boolean>(false)
const [walletAutoConnect, setWalletAutoConnect] = useLocalStorage<boolean | undefined>("walletAutoConnect", undefined)
const location = useLocation()
const navigate = useNavigate()

return (
<UserOptionsContainer>
<MenuItem
Expand All @@ -49,6 +54,15 @@ export const UserOptions: React.FC = () => {
</Grid>
</MenuItem>

<MenuItem item sx={{ cursor: "pointer" }} onClick={() => setShowIPFSModal(!showIPFSModal)}>
<Grid container gap={1} alignItems="center">
<Avatar sx={{ width: 28, height: 28, background: palette.grays[100] }}>
<ShortcutIcon sx={{ color: palette.grays[800], width: 20 }} />
</Avatar>
<Typography variant="body1">Update IPFS Node</Typography>
</Grid>
</MenuItem>

<MenuItem
item
sx={{ cursor: "pointer" }}
Expand Down Expand Up @@ -83,6 +97,8 @@ export const UserOptions: React.FC = () => {
</Typography>
</Grid>
</MenuItem>

<IPFSNodeModal open={showIPFSModal} onClose={() => setShowIPFSModal(false)} />
</UserOptionsContainer>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const CreateArticleView2: React.FC = () => {
const [authors, setAuthors] = useState<string[]>([])
const [articleImg, setArticleImg] = useState<File | undefined>(undefined)
const { control, handleSubmit, setValue } = useForm({ defaultValues: { description: "" } })
const { uploadContent, ipfs } = useIpfs()
const ipfs = useIpfs()
const { createArticle, updateArticle } = usePoster()
const {
indexing: createArticleIndexing,
Expand Down Expand Up @@ -62,8 +62,8 @@ export const CreateArticleView2: React.FC = () => {
let image
let hashArticle
let imageUrl
if (ipfs && articleImg) {
image = await uploadContent(articleImg)
if (articleImg) {
image = await ipfs.uploadContent(articleImg)
if (image.path) {
imageUrl = image.path
}
Expand All @@ -74,7 +74,7 @@ export const CreateArticleView2: React.FC = () => {
}

if (pinning && draftArticleText) {
hashArticle = await uploadContent(draftArticleText)
hashArticle = await ipfs.uploadContent(draftArticleText)
}

if (title && authors.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ export const PublicationsView: React.FC<PublicationsViewProps> = ({ updateChainI
setLoading(true)
const { title, description } = data
let image
if (ipfs.isReady && publicationImg) {
if (publicationImg) {
image = await ipfs.uploadContent(publicationImg)
}
if (title) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ const PublicationStyledTabs = styled(Tabs)({
})

export const PUBLICATIONS_TABS_OPTIONS = [
{ label: "articles", value: "articles" },
{ label: "Articles", value: "articles" },
{ label: "Permissions", value: "permissions" },
{ label: "Settings", value: "settings" },
]
export const PUBLICATIONS_TABS_WITHOUT_EDIT_OPTIONS = [
{ label: "articles", value: "articles" },
{ label: "Articles", value: "articles" },
{ label: "Permissions", value: "permissions" },
]

export const PUBLICATIONS_TABS_WITH_DELETE_OPTIONS = [
{ label: "articles", value: "articles" },
{ label: "Articles", value: "articles" },
{ label: "Permissions", value: "permissions" },
{ label: "Settings", value: "settings" },
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const SettingSection: React.FC<SettingsSectionProps> = ({ couldDelete, co
setLoading(true)
const { title, description } = data
let image
if (ipfs.isReady && draftPublicationImage) {
if (draftPublicationImage) {
image = await ipfs.uploadContent(draftPublicationImage)
}
if (!draftPublicationImage && publication?.image) {
Expand Down
Loading