1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

migrate to Next.js (#935)

* migrate to Next.js

* migrate scripts

* generate markdown pages

* make all the markdown work

* fix profile, fix image loading

* git+ssh → git+https, again

* bump packages

* maybe windows build fix

* add public to gitignore

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* Next.js v12! Webpack 5! No build hacks anymore

* json import fixes

* fixes

Co-authored-by: mihaisc <mihai.scarlat@smartcontrol.ro>
This commit is contained in:
Matthias Kretschmann 2021-10-27 11:27:14 +01:00
parent 032b3e1496
commit 3729c63581
Signed by: m
GPG Key ID: 606EEEF3C479A91F
154 changed files with 21781 additions and 52552 deletions

View File

@ -1,7 +1,7 @@
#GATSBY_INFURA_PROJECT_ID="xxx" #NEXT_INFURA_PROJECT_ID="xxx"
#GATSBY_MARKET_FEE_ADDRESS="0xxx" #NEXT_MARKET_FEE_ADDRESS="0xxx"
#GATSBY_PORTIS_ID="xxx" #NEXT_PORTIS_ID="xxx"
# #
@ -9,9 +9,9 @@
# #
# Toggle pricing options presented during price creation # Toggle pricing options presented during price creation
#GATSBY_ALLOW_FIXED_PRICING="true" #NEXT_ALLOW_FIXED_PRICING="true"
#GATSBY_ALLOW_DYNAMIC_PRICING="true" #NEXT_ALLOW_DYNAMIC_PRICING="true"
#GATSBY_ALLOW_FREE_PRICING="true" #NEXT_ALLOW_FREE_PRICING="true"
# Privacy Preference Center # Privacy Preference Center
#GATSBY_PRIVACY_PREFERENCE_CENTER="true" #NEXT_PRIVACY_PREFERENCE_CENTER="true"

View File

@ -27,6 +27,7 @@
"rules": { "rules": {
"react/prop-types": "off", "react/prop-types": "off",
"react/no-unused-prop-types": "off", "react/no-unused-prop-types": "off",
"react/jsx-no-bind": "off",
"@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-function-return-type": "off",
"no-use-before-define": "off", "no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": "error" "@typescript-eslint/no-use-before-define": "error"

View File

@ -36,7 +36,7 @@ jobs:
restore-keys: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}- restore-keys: ${{ runner.os }}-${{ matrix.node }}-build-${{ env.cache-name }}-
- run: npm ci - run: npm ci
- run: npm run apollo:codegen - run: npm run codegen:apollo
- run: npm run lint - run: npm run lint
# - run: npm test # - run: npm test
- run: npm run build - run: npm run build

View File

@ -16,8 +16,8 @@ jobs:
- run: npm run build - run: npm run build
env: env:
GATSBY_INFURA_PROJECT_ID: ${{ secrets.GATSBY_INFURA_PROJECT_ID }} NEXT_INFURA_PROJECT_ID: ${{ secrets.NEXT_INFURA_PROJECT_ID }}
GATSBY_PORTIS_ID: ${{ secrets.GATSBY_PORTIS_ID }} NEXT_PORTIS_ID: ${{ secrets.NEXT_PORTIS_ID }}
- run: npm run deploy:s3 - run: npm run deploy:s3
env: env:

8
.gitignore vendored
View File

@ -4,15 +4,13 @@ out
.idea .idea
.env .env
coverage coverage
dist
public
.cache .cache
storybook-static .next
public/storybook
.artifacts .artifacts
.vercel .vercel
repo-metadata.json repo-metadata.json
content/networks-metadata.json networks-metadata.json
src/@types/apollo src/@types/apollo
graphql.schema.json graphql.schema.json
src/@types/graph.types.ts src/@types/graph.types.ts
public

View File

@ -11,7 +11,7 @@
"typescriptreact" "typescriptreact"
], ],
"search.exclude": { "search.exclude": {
"**/.cache": true, "**/.next": true,
"**/public": true "**/out": true
} }
} }

View File

@ -36,7 +36,7 @@
## 🏄 Get Started ## 🏄 Get Started
The app is a React app built with [Gatsby.js](https://www.gatsbyjs.org) + TypeScript + CSS modules and will connect to Ocean remote components by default. The app is a React app built with [Next.js](https://nextjs.org) + TypeScript + CSS modules and will connect to Ocean remote components by default.
To start local development: To start local development:
@ -54,9 +54,6 @@ npm start
This will start the development server under This will start the development server under
`http://localhost:8000`. `http://localhost:8000`.
To explore the generated GraphQL data structure fire up the accompanying GraphiQL IDE under
`http://localhost:8000/__graphql`.
### Local components with Barge ### Local components with Barge
If you prefer to connect to locally running components instead of remote connections, you can spin up [`barge`](https://github.com/oceanprotocol/barge) and use a local Ganache network in another terminal before running `npm start`: If you prefer to connect to locally running components instead of remote connections, you can spin up [`barge`](https://github.com/oceanprotocol/barge) and use a local Ganache network in another terminal before running `npm start`:
@ -260,7 +257,7 @@ function Component() {
### Network Metadata ### Network Metadata
All displayed chain & network metadata is retrieved from `https://chainid.network` on build time and integrated into Gatsby's GraphQL layer. This data source is a community-maintained GitHub repository under [ethereum-lists/chains](https://github.com/ethereum-lists/chains). All displayed chain & network metadata is retrieved from `https://chainid.network` on build time and integrated into NEXT's GraphQL layer. This data source is a community-maintained GitHub repository under [ethereum-lists/chains](https://github.com/ethereum-lists/chains).
Within components this metadata can be queried for under `allNetworksMetadataJson`. The `useWeb3()` hook does this in the background to expose the final `networkDisplayName` for use in components: Within components this metadata can be queried for under `allNetworksMetadataJson`. The `useWeb3()` hook does this in the background to expose the final `networkDisplayName` for use in components:
@ -343,15 +340,15 @@ Everything else is made open according to the apache2 license. We look forward t
### Dynamic Pricing ### Dynamic Pricing
To allow publishers to set pricing as "Dynamic" you need to add the following environmental variable to your .env file: `GATSBY_ALLOW_DYNAMIC_PRICING="true"` (default). To allow publishers to set pricing as "Dynamic" you need to add the following environmental variable to your .env file: `NEXT_ALLOW_DYNAMIC_PRICING="true"` (default).
### Fixed Pricing ### Fixed Pricing
To allow publishers to set pricing as "Fixed" you need to add the following environmental variable to your .env file: `GATSBY_ALLOW_FIXED_PRICING="true"` (default). To allow publishers to set pricing as "Fixed" you need to add the following environmental variable to your .env file: `NEXT_ALLOW_FIXED_PRICING="true"` (default).
### Free Pricing ### Free Pricing
To allow publishers to set pricing as "Free" you need to add the following environmental variable to your .env file: `GATSBY_ALLOW_FREE_PRICING="true"` (default). To allow publishers to set pricing as "Free" you need to add the following environmental variable to your .env file: `NEXT_ALLOW_FREE_PRICING="true"` (default).
This allocates the datatokens to the [dispenser contract](https://github.com/oceanprotocol/contracts/blob/main/contracts/dispenser/Dispenser.sol) which dispenses data tokens to users for free. Publishers in your market will now be able to offer their datasets to users for free (excluding gas costs). This allocates the datatokens to the [dispenser contract](https://github.com/oceanprotocol/contracts/blob/main/contracts/dispenser/Dispenser.sol) which dispenses data tokens to users for free. Publishers in your market will now be able to offer their datasets to users for free (excluding gas costs).
@ -365,7 +362,7 @@ Feel free to adopt our provided privacy policies to your needs. Per default we c
### Privacy Preference Center ### Privacy Preference Center
Additionally, Ocean Market provides a privacy preference center for you to use. This feature is disabled per default since we do not use cookies requiring consent on our deployment of the market. However, if you need to add some functionality depending on cookies, you can simply enable this feature by changing the value of the `GATSBY_PRIVACY_PREFERENCE_CENTER` environmental variable to `"true"` in your `.env` file. This will enable a customizable cookie banner stating the use of your individual cookies. The content of this banner can be adjusted within the `content/gdpr.json` file. If no `optionalCookies` are provided, the privacy preference center will be set to a simpler version displaying only the `title`, `text` and `close`-button. This can be used to inform the user about the use of essential cookies, where no consent is needed. The privacy preference center supports two different styling options: `'small'` and `'default'`. Setting the style propertie to `'small'` will display a smaller cookie banner to the user at first, only showing the default styled privacy preference center upon the user's customization request. Additionally, Ocean Market provides a privacy preference center for you to use. This feature is disabled per default since we do not use cookies requiring consent on our deployment of the market. However, if you need to add some functionality depending on cookies, you can simply enable this feature by changing the value of the `NEXT_PRIVACY_PREFERENCE_CENTER` environmental variable to `"true"` in your `.env` file. This will enable a customizable cookie banner stating the use of your individual cookies. The content of this banner can be adjusted within the `content/gdpr.json` file. If no `optionalCookies` are provided, the privacy preference center will be set to a simpler version displaying only the `title`, `text` and `close`-button. This can be used to inform the user about the use of essential cookies, where no consent is needed. The privacy preference center supports two different styling options: `'small'` and `'default'`. Setting the style propertie to `'small'` will display a smaller cookie banner to the user at first, only showing the default styled privacy preference center upon the user's customization request.
Now your market users will be provided with additional options to toggle the use of your configured cookie consent categories. You can always retrieve the current consent status per category with the provided `useConsent()` hook. See below, how you can set your own custom cookies depending on the market user's consent. Feel free to adjust the provided utility functions for cookie usage provided in the `src/utils/cookies.ts` file to your needs. Now your market users will be provided with additional options to toggle the use of your configured cookie consent categories. You can always retrieve the current consent status per category with the provided `useConsent()` hook. See below, how you can set your own custom cookies depending on the market user's consent. Feel free to adjust the provided utility functions for cookie usage provided in the `src/utils/cookies.ts` file to your needs.

View File

@ -1,2 +0,0 @@
/asset/* /asset/index.html 200
/profile/* /profile/index.html 200

View File

@ -15,11 +15,11 @@ module.exports = {
// List of all supported chainIds. Used to populate the Chains user preferences list. // List of all supported chainIds. Used to populate the Chains user preferences list.
chainIdsSupported: [1, 3, 4, 137, 80001, 1287, 56, 2021000, 1285, 246], chainIdsSupported: [1, 3, 4, 137, 80001, 1287, 56, 2021000, 1285, 246],
infuraProjectId: process.env.GATSBY_INFURA_PROJECT_ID || 'xxx', infuraProjectId: process.env.NEXT_INFURA_PROJECT_ID || 'xxx',
// The ETH address the marketplace fee will be sent to. // The ETH address the marketplace fee will be sent to.
marketFeeAddress: marketFeeAddress:
process.env.GATSBY_MARKET_FEE_ADDRESS || process.env.NEXT_MARKET_FEE_ADDRESS ||
'0x9984b2453eC7D99a73A5B3a46Da81f197B753C8d', '0x9984b2453eC7D99a73A5B3a46Da81f197B753C8d',
// Used for conversion display, can be whatever coingecko API supports // Used for conversion display, can be whatever coingecko API supports
@ -48,13 +48,13 @@ module.exports = {
}, },
// Wallets // Wallets
portisId: process.env.GATSBY_PORTIS_ID || 'xxx', portisId: process.env.NEXT_PORTIS_ID || 'xxx',
// Used to show or hide the fixed, dynamic or free price options // Used to show or hide the fixed, dynamic or free price options
// tab to publishers during the price creation. // tab to publishers during the price creation.
allowFixedPricing: process.env.GATSBY_ALLOW_FIXED_PRICING || 'true', allowFixedPricing: process.env.NEXT_ALLOW_FIXED_PRICING || 'true',
allowDynamicPricing: process.env.GATSBY_ALLOW_DYNAMIC_PRICING || 'true', allowDynamicPricing: process.env.NEXT_ALLOW_DYNAMIC_PRICING || 'true',
allowFreePricing: process.env.GATSBY_ALLOW_FREE_PRICING || 'true', allowFreePricing: process.env.NEXT_ALLOW_FREE_PRICING || 'true',
// Set the default privacy policy to initially display // Set the default privacy policy to initially display
// this should be the slug of your default policy markdown file // this should be the slug of your default policy markdown file
@ -65,6 +65,5 @@ module.exports = {
// If set to true a gdpr.json file inside the content directory // If set to true a gdpr.json file inside the content directory
// is used to create and show a privacy preference center / cookie banner // is used to create and show a privacy preference center / cookie banner
// To learn more about how to configure and use this, please refer to the readme // To learn more about how to configure and use this, please refer to the readme
privacyPreferenceCenter: privacyPreferenceCenter: process.env.NEXT_PRIVACY_PREFERENCE_CENTER || 'false'
process.env.GATSBY_PRIVACY_PREFERENCE_CENTER || 'false'
} }

View File

@ -1,28 +1,26 @@
{ {
"site": { "siteTitle": "Ocean Market",
"siteTitle": "Ocean Market", "siteTagline": "A marketplace to find, publish and trade data sets in the Ocean Network.",
"siteTagline": "A marketplace to find, publish and trade data sets in the Ocean Network.", "siteUrl": "https://market.oceanprotocol.com",
"siteUrl": "https://market.oceanprotocol.com", "siteIcon": "node_modules/@oceanprotocol/art/logo/favicon-white.png",
"siteIcon": "node_modules/@oceanprotocol/art/logo/favicon-white.png", "siteImage": "../src/@images/share.png",
"siteImage": "../src/@images/share.png", "copyright": "All Rights Reserved. Powered by [Ocean Protocol](https://oceanprotocol.com)",
"copyright": "All Rights Reserved. Powered by [Ocean Protocol](https://oceanprotocol.com)", "menu": [
"menu": [ {
{ "name": "Publish",
"name": "Publish", "link": "/publish"
"link": "/publish"
},
{
"name": "Profile",
"link": "/profile"
}
],
"warning": {
"main": "We are in beta. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).",
"polygonPublish": "Only republish data sets with a pool from ETH Mainnet into Polygon/Matic if the liquidity is **less than or equal to 1000 OCEAN in the original pool**. Doing otherwise will lead to [purgatory](https://github.com/oceanprotocol/list-purgatory) for the data set in Polygon/Matic."
}, },
"announcement": { {
"main": "Ocean Market is [available on Polygon](https://blog.oceanprotocol.com/ocean-on-polygon-network-8abad19cbf47).", "name": "Profile",
"polygon": "Polygon/Matic EVM support is in early stages. [Use the Polygon Bridge](https://docs.oceanprotocol.com/tutorials/polygon-bridge/) to get mOCEAN." "link": "/profile"
} }
],
"warning": {
"main": "We are in beta. Please familiarize yourself with [the market](https://oceanprotocol.com/technology/marketplaces), [the risks](https://blog.oceanprotocol.com/on-staking-on-data-in-ocean-market-3d8e09eb0a13), and the [Terms of Use](/terms).",
"polygonPublish": "Only republish data sets with a pool from ETH Mainnet into Polygon/Matic if the liquidity is **less than or equal to 1000 OCEAN in the original pool**. Doing otherwise will lead to [purgatory](https://github.com/oceanprotocol/list-purgatory) for the data set in Polygon/Matic."
},
"announcement": {
"main": "Ocean Market is [available on Polygon](https://blog.oceanprotocol.com/ocean-on-polygon-network-8abad19cbf47).",
"polygon": "Polygon/Matic EVM support is in early stages. [Use the Polygon Bridge](https://docs.oceanprotocol.com/tutorials/polygon-bridge/) to get mOCEAN."
} }
} }

View File

@ -1,5 +0,0 @@
import wrapPageElementWithStyles from './src/components/App/wrapPageElement'
import ContextProviders from './src/components/App/ContextProviders'
export const wrapPageElement = wrapPageElementWithStyles
export const wrapRootElement = ContextProviders

View File

@ -1,83 +0,0 @@
require('dotenv').config()
const siteContent = require('./content/site.json')
const appConfig = require('./app.config')
module.exports = {
siteMetadata: {
...siteContent.site,
appConfig: {
...appConfig
}
},
plugins: [
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'content',
path: `${__dirname}/content`
}
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'images',
path: `${__dirname}/src/@images`
}
},
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'art',
path: `${__dirname}/node_modules/@oceanprotocol/art/`
}
},
{
resolve: 'gatsby-plugin-sharp',
options: {
defaultQuality: 80
}
},
'gatsby-transformer-sharp',
'gatsby-transformer-json',
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [`gatsby-remark-autolink-headers`]
}
},
{
resolve: 'gatsby-plugin-svgr',
options: {
icon: false,
svgoConfig: {
plugins: [{ removeViewBox: false }]
}
}
},
'gatsby-plugin-react-helmet',
'gatsby-plugin-remove-trailing-slashes',
{
// https://www.gatsbyjs.org/packages/gatsby-plugin-manifest/#using-with-gatsby-plugin-offline
resolve: 'gatsby-plugin-manifest',
options: {
name: siteContent.site.siteTitle,
short_name: siteContent.site.siteTitle,
start_url: '/',
background_color: '#ffffff',
theme_color: '#141414',
icon: siteContent.site.siteIcon,
display: 'standalone',
cache_busting_mode: 'none'
}
},
'gatsby-plugin-webpack-size',
{
resolve: 'gatsby-plugin-use-dark-mode',
options: {
...appConfig.darkModeConfig,
minify: true
}
}
]
}

View File

@ -1,73 +0,0 @@
const createMarkdownFields = require('./gatsby/createMarkdownFields')
const createMarkdownPages = require('./gatsby/createMarkdownPages')
const createTypes = require('./gatsby/createTypes')
const execSync = require('child_process').execSync
const path = require('path')
// Write out repo metadata
execSync(`node ./scripts/write-repo-metadata > repo-metadata.json`, {
stdio: 'inherit'
})
// Generate GraphQL typings for urql
// execSync(`npm run graphql:graphTypes`, { stdio: 'inherit' })
// Generate Apollo typings
execSync(`npm run apollo:codegen`, { stdio: 'inherit' })
// Fetch EVM networks metadata
execSync(
`node ./scripts/write-networks-metadata > content/networks-metadata.json`,
{
stdio: 'inherit'
}
)
exports.sourceNodes = ({ actions }) => {
createTypes(actions)
}
exports.onCreateNode = ({ node, actions, getNode }) => {
createMarkdownFields(node, actions, getNode)
}
exports.createPages = async ({ graphql, actions }) => {
await createMarkdownPages(graphql, actions)
}
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
// page.matchPath is a special key that's used for matching pages
// only on the client.
const handleClientSideOnlyAsset = page.path.match(/^\/asset/)
const handleClientSideOnlyAccount = page.path.match(/^\/profile/)
if (handleClientSideOnlyAsset) {
page.matchPath = '/asset/*'
// Update the page.
createPage(page)
} else if (handleClientSideOnlyAccount) {
page.matchPath = '/profile/*'
createPage(page)
}
}
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
resolve: {
alias: {
'@shared': path.resolve(__dirname, 'src/components/@shared'),
'@hooks': path.resolve(__dirname, 'src/@hooks'),
'@context': path.resolve(__dirname, 'src/@context'),
'@images': path.resolve(__dirname, 'src/@images'),
'@utils': path.resolve(__dirname, 'src/@utils')
}
},
node: {
// 'fs' fix for ocean.js
fs: 'empty'
},
// fix for 'got'/'swarm-js' dependency
externals: ['got']
})
}

View File

@ -1,5 +0,0 @@
import wrapPageElementWithStyles from './src/components/App/wrapPageElement'
import ContextProviders from './src/components/App/ContextProviders'
export const wrapPageElement = wrapPageElementWithStyles
export const wrapRootElement = ContextProviders

View File

@ -1,27 +0,0 @@
const { createFilePath } = require('gatsby-source-filesystem')
function createMarkdownFields(node, actions, getNode) {
const { createNodeField } = actions
// Automatically create slugs for specific node types,
// relative to ./content/pages/
const { type } = node.internal
if (type === 'MarkdownRemark') {
// Create a slug from the file path & name
const slug = createFilePath({
node,
getNode,
basePath: 'pages/',
trailingSlash: false
})
createNodeField({
name: 'slug',
node,
value: slug
})
}
}
module.exports = createMarkdownFields

View File

@ -1,42 +0,0 @@
const path = require('path')
async function createMarkdownPages(graphql, actions) {
const { createPage } = actions
const markdownPageTemplate = path.resolve(
'./src/components/@shared/Page/PageMarkdown.tsx'
)
// Grab all markdown files with a frontmatter title defined
const markdownResult = await graphql(`
{
allMarkdownRemark(filter: { frontmatter: { title: { ne: "" } } }) {
edges {
node {
fields {
slug
}
}
}
}
}
`)
if (markdownResult.errors) {
throw markdownResult.errors
}
// Create markdown pages.
const markdownPages = markdownResult.data.allMarkdownRemark.edges
markdownPages.forEach((page) => {
createPage({
path: page.node.fields.slug,
component: markdownPageTemplate,
context: {
slug: page.node.fields.slug
}
})
})
}
module.exports = createMarkdownPages

View File

@ -1,27 +0,0 @@
function createTypes(actions) {
const { createTypes } = actions
// Extend ContentJson to support optional field "optionalCookies" in gdpr.json
// Extend PublishJsonData to support optional fields for disclaimers
const typeDefs = `
type ContentJson implements Node {
accept: String
reject: String
close: String
configure: String
optionalCookies: [Cookie!]
}
type Cookie {
title: String!
desc: String!
cookieName: String!
}
type PublishJsonData implements Node {
disclaimer: String
disclaimerValues: [String!]
}
`
createTypes(typeDefs)
}
module.exports = createTypes

6
next-env.d.ts vendored Normal file
View File

@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

42
next.config.js Normal file
View File

@ -0,0 +1,42 @@
module.exports = (phase, { defaultConfig }) => {
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
webpack: (config, options) => {
config.module.rules.push(
{
test: /\.svg$/,
issuer: /\.(tsx|ts)$/,
use: [{ loader: '@svgr/webpack', options: { icon: true } }]
},
{
test: /\.gif$/,
// yay for webpack 5
// https://webpack.js.org/guides/asset-management/#loading-images
type: 'asset/resource'
}
)
// for old ocean.js, most likely can be removed later on
config.resolve.fallback = {
fs: false,
crypto: false,
os: false,
stream: false,
http: false,
https: false
}
return typeof defaultConfig.webpack === 'function'
? defaultConfig.webpack(config, options)
: config
}
// Prefer loading of ES Modules over CommonJS
// https://nextjs.org/blog/next-11-1#es-modules-support
// experimental: { esmExternals: true }
}
return nextConfig
}

71273
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,20 +5,19 @@
"license": "Apache-2.0", "license": "Apache-2.0",
"homepage": "https://market.oceanprotocol.com", "homepage": "https://market.oceanprotocol.com",
"scripts": { "scripts": {
"start": "gatsby develop --host 0.0.0.0", "start": "npm run pregenerate && next dev -p 8000",
"build": "gatsby build && cp _redirects public/_redirects", "build": "npm run pregenerate && next build",
"serve": "serve -s public/", "serve": "serve -s public/",
"test-graphql": "npm run graphql:graphTypes && npm run lint", "pregenerate": "bash scripts/pregenerate.sh",
"test": "npm run apollo:codegen && npm run lint", "test": "npm run pregenerate && npm run lint && npm run type-check",
"lint": "npm run write:repoMetadata && eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx . && npm run type-check", "test:graphql": "npm run codegen:graphql && npm run lint",
"lint": "eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx .",
"format": "prettier --ignore-path .gitignore './**/*.{css,yml,js,ts,tsx,json}' --write", "format": "prettier --ignore-path .gitignore './**/*.{css,yml,js,ts,tsx,json}' --write",
"type-check": "tsc --noEmit", "type-check": "tsc --noEmit",
"analyze": "npm run build && source-map-explorer 'public/*.js'", "deploy:s3": "bash scripts/deploy-s3.sh",
"write:repoMetadata": "node ./scripts/write-repo-metadata > repo-metadata.json",
"deploy:s3": "./scripts/deploy-s3.sh",
"postinstall": "husky install", "postinstall": "husky install",
"apollo:codegen": "apollo client:codegen --target typescript --tsFileExtension=d.ts --outputFlat src/@types/apollo/", "codegen:apollo": "apollo client:codegen --target typescript --tsFileExtension=d.ts --outputFlat src/@types/apollo/",
"graphql:graphTypes": "graphql-codegen --config codegen.yml" "codegen:graphql": "graphql-codegen --config codegen.yml"
}, },
"dependencies": { "dependencies": {
"@coingecko/cryptoformat": "^0.4.4", "@coingecko/cryptoformat": "^0.4.4",
@ -26,12 +25,11 @@
"@oceanprotocol/art": "^3.2.0", "@oceanprotocol/art": "^3.2.0",
"@oceanprotocol/lib": "^0.19.2", "@oceanprotocol/lib": "^0.19.2",
"@oceanprotocol/typographies": "^0.1.0", "@oceanprotocol/typographies": "^0.1.0",
"@portis/web3": "^4.1.0", "@portis/web3": "^4.0.6",
"@sindresorhus/slugify": "^2.1.0",
"@tippyjs/react": "^4.2.5", "@tippyjs/react": "^4.2.5",
"@urql/introspection": "^0.3.0", "@urql/introspection": "^0.3.0",
"@walletconnect/web3-provider": "^1.6.6", "@walletconnect/web3-provider": "^1.6.6",
"axios": "^0.23.0", "axios": "^0.24.0",
"chart.js": "^2.9.4", "chart.js": "^2.9.4",
"classnames": "^2.3.1", "classnames": "^2.3.1",
"date-fns": "^2.25.0", "date-fns": "^2.25.0",
@ -42,28 +40,13 @@
"ethereum-blockies": "github:MyEtherWallet/blockies", "ethereum-blockies": "github:MyEtherWallet/blockies",
"filesize": "^8.0.3", "filesize": "^8.0.3",
"formik": "^2.2.9", "formik": "^2.2.9",
"gatsby": "^2.32.13", "gray-matter": "^4.0.3",
"gatsby-image": "^2.9.0",
"gatsby-plugin-manifest": "^2.10.0",
"gatsby-plugin-react-helmet": "^3.8.0",
"gatsby-plugin-remove-trailing-slashes": "^2.8.0",
"gatsby-plugin-sharp": "^2.14.4",
"gatsby-plugin-svgr": "^2.1.0",
"gatsby-plugin-use-dark-mode": "^1.3.0",
"gatsby-plugin-webpack-size": "^2.0.1",
"gatsby-remark-autolink-headers": "^4.8.0",
"gatsby-source-filesystem": "^2.9.0",
"gatsby-source-graphql": "^2.12.0",
"gatsby-transformer-json": "^2.9.0",
"gatsby-transformer-remark": "^2.16.1",
"gatsby-transformer-sharp": "^2.12.1",
"graphql": "14.7.0",
"graphql-schema-typescript": "^1.5.2",
"is-url-superb": "^6.0.0", "is-url-superb": "^6.0.0",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"lodash.omit": "^4.5.0", "lodash.omit": "^4.5.0",
"next": "^12.0.1",
"query-string": "^7.0.1", "query-string": "^7.0.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-chartjs-2": "^2.11.2", "react-chartjs-2": "^2.11.2",
@ -71,17 +54,17 @@
"react-data-table-component": "^6.11.7", "react-data-table-component": "^6.11.7",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-dotdotdot": "^1.3.1", "react-dotdotdot": "^1.3.1",
"react-helmet": "^6.1.0",
"react-markdown": "^6.0.2",
"react-modal": "^3.14.3", "react-modal": "^3.14.3",
"react-paginate": "^7.1.3", "react-paginate": "^7.1.3",
"react-spring": "^9.3.0", "react-spring": "^9.3.0",
"react-tabs": "^3.2.2", "react-tabs": "^3.2.2",
"react-toastify": "^7.0.4", "react-toastify": "^8.0.3",
"remark": "^13.0.0",
"remark-gfm": "^1.0.0",
"remark-html": "^13.0.1",
"remove-markdown": "^0.3.0", "remove-markdown": "^0.3.0",
"shortid": "^2.2.16",
"slugify": "^1.6.1", "slugify": "^1.6.1",
"swr": "^0.5.6", "swr": "^1.0.1",
"urql": "^2.0.5", "urql": "^2.0.5",
"use-dark-mode": "^2.3.1", "use-dark-mode": "^2.3.1",
"web3": "^1.6.0", "web3": "^1.6.0",
@ -89,26 +72,24 @@
"yup": "^0.32.11" "yup": "^0.32.11"
}, },
"devDependencies": { "devDependencies": {
"@graphql-codegen/cli": "1.21.6", "@graphql-codegen/cli": "^2.2.1",
"@graphql-codegen/introspection": "1.18.2", "@graphql-codegen/introspection": "^2.1.0",
"@graphql-codegen/typescript": "1.22.4", "@graphql-codegen/typescript": "^2.2.4",
"@graphql-codegen/typescript-operations": "^1.18.3", "@graphql-codegen/typescript-operations": "^2.1.8",
"@graphql-codegen/typescript-react-apollo": "2.3.0", "@graphql-codegen/typescript-react-apollo": "^3.1.6",
"@svgr/webpack": "^5.5.0", "@svgr/webpack": "^5.5.0",
"@types/chart.js": "^2.9.32", "@types/chart.js": "^2.9.32",
"@types/jest": "^26.0.23", "@types/js-cookie": "^3.0.0",
"@types/js-cookie": "^2.2.7",
"@types/loadable__component": "^5.13.1", "@types/loadable__component": "^5.13.1",
"@types/lodash.debounce": "^4.0.3", "@types/lodash.debounce": "^4.0.3",
"@types/lodash.omit": "^4.5.6", "@types/lodash.omit": "^4.5.6",
"@types/node": "^15.6.1", "@types/node": "^16.11.5",
"@types/react": "^17.0.8", "@types/react": "^17.0.32",
"@types/react-helmet": "^6.1.1", "@types/react-dom": "^17.0.10",
"@types/react-modal": "^3.12.0", "@types/react-modal": "^3.13.1",
"@types/react-paginate": "^7.1.0", "@types/react-paginate": "^7.1.1",
"@types/react-tabs": "^2.3.2", "@types/react-tabs": "^2.3.3",
"@types/remove-markdown": "^0.3.0", "@types/remove-markdown": "^0.3.1",
"@types/shortid": "0.0.29",
"@types/yup": "^0.29.11", "@types/yup": "^0.29.11",
"@typescript-eslint/eslint-plugin": "^4.26.0", "@typescript-eslint/eslint-plugin": "^4.26.0",
"@typescript-eslint/parser": "^4.26.0", "@typescript-eslint/parser": "^4.26.0",
@ -116,14 +97,14 @@
"eslint": "^7.27.0", "eslint": "^7.27.0",
"eslint-config-oceanprotocol": "^1.5.0", "eslint-config-oceanprotocol": "^1.5.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.24.0", "eslint-plugin-react": "^7.24.0",
"eslint-plugin-react-hooks": "^4.2.0", "eslint-plugin-react-hooks": "^4.2.0",
"file-loader": "^6.2.0",
"husky": "^7.0.2", "husky": "^7.0.2",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"pretty-quick": "^3.1.1", "pretty-quick": "^3.1.1",
"serve": "^12.0.1", "serve": "^12.0.1",
"source-map-explorer": "^2.5.2",
"typescript": "^4.4.4" "typescript": "^4.4.4"
}, },
"repository": { "repository": {

13
scripts/pregenerate.sh Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Write out repo metadata
node ./scripts/write-repo-metadata > content/repo-metadata.json
# Generate GraphQL typings for urql
# npm run codegen:graphql
# Generate Apollo typings
npm run codegen:apollo
# Fetch EVM networks metadata
node ./scripts/write-networks-metadata > content/networks-metadata.json

View File

@ -180,5 +180,5 @@ function AssetProvider({
// Helper hook to access the provider values // Helper hook to access the provider values
const useAsset = (): AssetProviderValue => useContext(AssetContext) const useAsset = (): AssetProviderValue => useContext(AssetContext)
export { AssetProvider, useAsset, AssetProviderValue, AssetContext } export { AssetProvider, useAsset, AssetContext }
export default AssetProvider export default AssetProvider

View File

@ -134,5 +134,5 @@ function ConsentProvider({ children }: { children: ReactNode }): ReactElement {
const useConsent = (): ConsentProviderValue => useContext(ConsentContext) const useConsent = (): ConsentProviderValue => useContext(ConsentContext)
export { ConsentProvider, useConsent, ConsentProviderValue, ConsentContext } export { ConsentProvider, useConsent, ConsentContext }
export default ConsentProvider export default ConsentProvider

View File

@ -109,5 +109,5 @@ function OceanProvider({ children }: { children: ReactNode }): ReactElement {
// Helper hook to access the provider values // Helper hook to access the provider values
const useOcean = (): OceanProviderValue => useContext(OceanContext) const useOcean = (): OceanProviderValue => useContext(OceanContext)
export { OceanProvider, useOcean, OceanProviderValue, OceanContext } export { OceanProvider, useOcean, OceanContext }
export default OceanProvider export default OceanProvider

View File

@ -59,4 +59,4 @@ export default function PricesProvider({
// Helper hook to access the provider values // Helper hook to access the provider values
const usePrices = (): PricesValue => useContext(PricesContext) const usePrices = (): PricesValue => useContext(PricesContext)
export { PricesProvider, usePrices, PricesValue } export { PricesProvider, usePrices }

View File

@ -320,5 +320,5 @@ function ProfileProvider({
// Helper hook to access the provider values // Helper hook to access the provider values
const useProfile = (): ProfileProviderValue => useContext(ProfileContext) const useProfile = (): ProfileProviderValue => useContext(ProfileContext)
export { ProfileProvider, useProfile, ProfileProviderValue, ProfileContext } export { ProfileProvider, useProfile, ProfileContext }
export default ProfileProvider export default ProfileProvider

View File

@ -166,4 +166,4 @@ function UserPreferencesProvider({
const useUserPreferences = (): UserPreferencesValue => const useUserPreferences = (): UserPreferencesValue =>
useContext(UserPreferencesContext) useContext(UserPreferencesContext)
export { UserPreferencesProvider, useUserPreferences, UserPreferencesValue } export { UserPreferencesProvider, useUserPreferences }

View File

@ -47,7 +47,7 @@ const web3ModalTheme = {
hover: 'var(--background-highlight)' hover: 'var(--background-highlight)'
} }
// HEADS UP! We inline-require some packages so the Gatsby SSR build does not break. // HEADS UP! We inline-require some packages so the SSR build does not break.
// We only need them client-side. // We only need them client-side.
const providerOptions = isBrowser const providerOptions = isBrowser
? { ? {
@ -363,5 +363,5 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement {
// Helper hook to access the provider values // Helper hook to access the provider values
const useWeb3 = (): Web3ProviderValue => useContext(Web3Context) const useWeb3 = (): Web3ProviderValue => useContext(Web3Context)
export { Web3Provider, useWeb3, Web3ProviderValue, Web3Context } export { Web3Provider, useWeb3, Web3Context }
export default Web3Provider export default Web3Provider

View File

@ -44,5 +44,5 @@ function useAccountPurgatory(accountId: string): UseAccountPurgatory {
} }
} }
export { useAccountPurgatory, UseAccountPurgatory } export { useAccountPurgatory }
export default useAccountPurgatory export default useAccountPurgatory

View File

@ -100,5 +100,5 @@ function useConsume(): UseConsume {
return { consume, consumeStep, consumeStepText, consumeError, isLoading } return { consume, consumeStep, consumeStepText, consumeError, isLoading }
} }
export { useConsume, UseConsume } export { useConsume }
export default useConsume export default useConsume

View File

@ -1,4 +1,4 @@
import { useStaticQuery, graphql } from 'gatsby' import gdprContent from '../../content/gdpr.json'
export interface UseGdprMetadata { export interface UseGdprMetadata {
title: string title: string
@ -7,7 +7,7 @@ export interface UseGdprMetadata {
reject: string reject: string
close: string close: string
configure: string configure: string
placeholder: string placeholder?: string
optionalCookies?: { optionalCookies?: {
title: string title: string
desc: string desc: string
@ -15,32 +15,6 @@ export interface UseGdprMetadata {
}[] }[]
} }
const query = graphql`
query GdprQuery {
gdpr: allFile(filter: { relativePath: { eq: "gdpr.json" } }) {
edges {
node {
childContentJson {
title
text
accept
reject
close
configure
optionalCookies {
title
desc
cookieName
}
}
}
}
}
}
`
export function useGdprMetadata(): UseGdprMetadata { export function useGdprMetadata(): UseGdprMetadata {
const data = useStaticQuery(query) return { ...gdprContent }
return { ...data.gdpr.edges[0].node.childContentJson }
} }

View File

@ -16,5 +16,5 @@ export const networkDataGaiaX: EthereumListsChain = {
'https://faucet.gx.gaiaxtestnet.oceanprotocol.com/' 'https://faucet.gx.gaiaxtestnet.oceanprotocol.com/'
], ],
infoURL: 'https://www.gaia-x.eu', infoURL: 'https://www.gaia-x.eu',
explorers: [{ url: '' }] explorers: [{ name: '', url: '', standard: '' }]
} }

View File

@ -1,35 +1,8 @@
import { useStaticQuery, graphql } from 'gatsby'
import { UseNetworkMetadata } from './types' import { UseNetworkMetadata } from './types'
import networkdata from '../../../content/networks-metadata.json'
const networksQuery = graphql`
query {
allNetworksMetadataJson {
edges {
node {
chain
network
networkId
chainId
rpc
explorers {
url
}
nativeCurrency {
name
symbol
decimals
}
}
}
}
}
`
export default function useNetworkMetadata(): UseNetworkMetadata { export default function useNetworkMetadata(): UseNetworkMetadata {
const data = useStaticQuery(networksQuery) const networksList: EthereumListsChain[] = networkdata
const networksList: { node: EthereumListsChain }[] =
data.allNetworksMetadataJson.edges
return { networksList } return { networksList }
} }

View File

@ -1,3 +1,3 @@
export interface UseNetworkMetadata { export interface UseNetworkMetadata {
networksList: { node: EthereumListsChain }[] networksList: EthereumListsChain[]
} }

View File

@ -33,21 +33,21 @@ export function getNetworkDisplayName(
} }
export function getNetworkDataById( export function getNetworkDataById(
data: { node: EthereumListsChain }[], data: EthereumListsChain[],
networkId: number networkId: number
): EthereumListsChain { ): EthereumListsChain {
if (!networkId) return if (!networkId) return
const networkData = data.filter( const networkData = data.filter(
({ node }: { node: EthereumListsChain }) => node.chainId === networkId (chain: EthereumListsChain) => chain.chainId === networkId
) )
return networkId === 2021000 ? networkDataGaiaX : networkData[0]?.node return networkId === 2021000 ? networkDataGaiaX : networkData[0]
} }
export function filterNetworksByType( export function filterNetworksByType(
type: 'mainnet' | 'testnet', type: 'mainnet' | 'testnet',
chainIds: number[], chainIds: number[],
networksList: { node: EthereumListsChain }[] networksList: EthereumListsChain[]
): number[] { ): number[] {
const finalNetworks = chainIds.filter((chainId: number) => { const finalNetworks = chainIds.filter((chainId: number) => {
const networkData = getNetworkDataById(networksList, chainId) const networkData = getNetworkDataById(networksList, chainId)

View File

@ -257,7 +257,7 @@ function usePricing(): UsePricing {
`${dtAmount}`, `${dtAmount}`,
weightOnDataToken, weightOnDataToken,
`${oceanAmount}`, `${oceanAmount}`,
swapFee `${swapFee}`
) )
.next((step: number) => setStep(step, 'pool', ddo)) .next((step: number) => setStep(step, 'pool', ddo))
: type === 'fixed' : type === 'fixed'
@ -292,5 +292,5 @@ function usePricing(): UsePricing {
} }
} }
export { usePricing, UsePricing } export { usePricing }
export default usePricing export default usePricing

View File

@ -1,4 +1,4 @@
import { useStaticQuery, graphql } from 'gatsby' import privacyContent from '../../content/pages/privacy/policies.json'
export interface UsePrivacyMetadata { export interface UsePrivacyMetadata {
policies: { policies: {
@ -14,26 +14,6 @@ export interface UsePrivacyMetadata {
}[] }[]
} }
const query = graphql`
{
privacyJson {
policies {
policy
date
language
params {
updated
dateFormat
tocHeader
languageLabel
}
}
}
}
`
export function usePrivacyMetadata(): UsePrivacyMetadata { export function usePrivacyMetadata(): UsePrivacyMetadata {
const data = useStaticQuery(query) return { ...privacyContent }
return { ...data.privacyJson }
} }

View File

@ -11,7 +11,7 @@ import { useOcean } from '@context/Ocean'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { getOceanConfig } from '@utils/ocean' import { getOceanConfig } from '@utils/ocean'
interface DataTokenOptions { export interface DataTokenOptions {
cap?: string cap?: string
name?: string name?: string
symbol?: string symbol?: string
@ -161,5 +161,5 @@ function usePublish(): UsePublish {
} }
} }
export { usePublish, UsePublish, DataTokenOptions } export { usePublish }
export default usePublish export default usePublish

View File

@ -1,75 +1,11 @@
import { useStaticQuery, graphql } from 'gatsby'
import { UseSiteMetadata } from './types' import { UseSiteMetadata } from './types'
import siteContent from '../../../content/site.json'
const query = graphql` import siteConfig from '../../../app.config'
query {
site {
siteMetadata {
siteTitle
siteTagline
siteUrl
siteIcon
copyright
menu {
name
link
}
warning {
main
polygonPublish
}
announcement {
main
polygon
}
appConfig {
metadataCacheUri
infuraProjectId
chainIds
chainIdsSupported
marketFeeAddress
currencies
portisId
allowFixedPricing
allowDynamicPricing
allowFreePricing
defaultPrivacyPolicySlug
privacyPreferenceCenter
darkModeConfig {
classNameDark
classNameLight
storageKey
}
}
}
}
siteImage: allFile(filter: { relativePath: { eq: "site.json" } }) {
edges {
node {
childContentJson {
site {
siteImage {
childImageSharp {
original {
src
}
}
}
}
}
}
}
}
}
`
export function useSiteMetadata(): UseSiteMetadata { export function useSiteMetadata(): UseSiteMetadata {
const data = useStaticQuery(query)
const siteMeta: UseSiteMetadata = { const siteMeta: UseSiteMetadata = {
...data.siteImage.edges[0].node.childContentJson.site, ...siteContent,
...data.site.siteMetadata appConfig: siteConfig
} }
return siteMeta return siteMeta

View File

@ -3,7 +3,7 @@ export interface UseSiteMetadata {
siteTagline: string siteTagline: string
siteUrl: string siteUrl: string
siteIcon: string siteIcon: string
siteImage: { childImageSharp: { original: { src: string } } } siteImage: string
copyright: string copyright: string
menu: { menu: {
name: string name: string

View File

@ -9,7 +9,7 @@ interface EthereumListsChain {
rpc: string[] rpc: string[]
infoURL: string infoURL: string
faucets: string[] faucets: string[]
explorers: [{ url: string }] explorers?: { name: string; url: string; standard: string }[]
} }
interface NetworkObject { interface NetworkObject {

View File

@ -1,15 +0,0 @@
declare module '*.module.css' {
const classes: { [key: string]: string }
export default classes
}
declare module '*.svg' {
import * as React from 'react'
export const ReactComponent: React.FunctionComponent<
React.SVGProps<SVGSVGElement>
>
const src: string
export default src
}
declare module '*.gif'

View File

@ -3,7 +3,7 @@ import {
DID, DID,
Logger, Logger,
publisherTrustedAlgorithm as PublisherTrustedAlgorithm publisherTrustedAlgorithm as PublisherTrustedAlgorithm
} from '@oceanprotocol/lib/' } from '@oceanprotocol/lib'
import { AssetSelectionAsset } from '@shared/Form/FormFields/AssetSelection' import { AssetSelectionAsset } from '@shared/Form/FormFields/AssetSelection'
import { PriceList, getAssetsPriceList } from './subgraph' import { PriceList, getAssetsPriceList } from './subgraph'
import axios, { CancelToken, AxiosResponse } from 'axios' import axios, { CancelToken, AxiosResponse } from 'axios'

12
src/@utils/markdown.ts Normal file
View File

@ -0,0 +1,12 @@
import remark from 'remark'
import remarkHtml from 'remark-html'
import remarkGfm from 'remark-gfm'
export function markdownToHtml(markdown: string): string {
const result = remark()
.use(remarkGfm)
.use(remarkHtml) // serializes through remark-rehype and rehype-stringify
.processSync(markdown).contents
return result.toString()
}

View File

@ -0,0 +1,35 @@
import fs from 'fs'
import { join } from 'path'
import matter from 'gray-matter'
//
// Next.js specifics to be used in getStaticProps / getStaticPaths
// to automatically generate pages from Markdown files in `src/pages/[slug].tsx`.
//
const pagesDirectory = join(process.cwd(), 'content', 'pages')
export interface PageData {
slug: string
frontmatter: { [key: string]: any }
content: string
}
export function getPageBySlug(slug: string, subDir?: string): PageData {
const realSlug = slug.replace(/\.md$/, '')
const fullPath = subDir
? join(pagesDirectory, subDir, `${realSlug}.md`)
: join(pagesDirectory, `${realSlug}.md`)
const fileContents = fs.readFileSync(fullPath, 'utf8')
const { data, content } = matter(fileContents)
return { slug: realSlug, frontmatter: { ...data }, content }
}
export function getAllPages(subDir?: string): PageData[] {
const slugs = fs
.readdirSync(join(pagesDirectory, subDir || ''))
.filter((slug) => slug.includes('.md'))
const pages = slugs.map((slug) => getPageBySlug(slug, subDir))
return pages
}

View File

@ -1,7 +1,7 @@
import axios from 'axios' import axios from 'axios'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import isUrl from 'is-url-superb' import isUrl from 'is-url-superb'
import slugify from '@sindresorhus/slugify' import slugify from 'slugify'
import { DDO, MetadataAlgorithm, Logger } from '@oceanprotocol/lib' import { DDO, MetadataAlgorithm, Logger } from '@oceanprotocol/lib'
import { FormPublishData } from '../components/Publish/_types' import { FormPublishData } from '../components/Publish/_types'
@ -97,72 +97,72 @@ function getAlgorithmFileExtension(fileUrl: string): string {
return splitedFileUrl[splitedFileUrl.length - 1] return splitedFileUrl[splitedFileUrl.length - 1]
} }
export function transformPublishFormToMetadata( // export function transformPublishFormToMetadata(
{ // {
name, // name,
author, // author,
description, // description,
tags, // tags,
links, // links,
termsAndConditions, // termsAndConditions,
files // files
}: Partial<FormPublishData>, // }: Partial<FormPublishData>,
ddo?: DDO // ddo?: DDO
): MetadataMarket { // ): MetadataMarket {
const currentTime = dateToStringNoMS(new Date()) // const currentTime = dateToStringNoMS(new Date())
const metadata: MetadataMarket = { // const metadata: MetadataMarket = {
main: { // main: {
name, // name,
author, // author,
dateCreated: ddo ? ddo.created : currentTime, // dateCreated: ddo ? ddo.created : currentTime,
datePublished: '', // datePublished: '',
files: typeof files !== 'string' && files, // files: typeof files !== 'string' && files,
license: 'https://market.oceanprotocol.com/terms' // license: 'https://market.oceanprotocol.com/terms'
}, // },
additionalInformation: { // additionalInformation: {
description, // description,
tags: transformTags(tags), // tags: transformTags(tags),
links: typeof links !== 'string' ? links : [], // links: typeof links !== 'string' ? links : [],
termsAndConditions // termsAndConditions
} // }
} // }
return metadata // return metadata
} // }
async function isDockerHubImageValid( // async function isDockerHubImageValid(
image: string, // image: string,
tag: string // tag: string
): Promise<boolean> { // ): Promise<boolean> {
try { // try {
const response = await axios.post( // const response = await axios.post(
`https://dockerhub-proxy.oceanprotocol.com`, // `https://dockerhub-proxy.oceanprotocol.com`,
{ // {
image, // image,
tag // tag
} // }
) // )
if ( // if (
!response || // !response ||
response.status !== 200 || // response.status !== 200 ||
response.data.status !== 'success' // response.data.status !== 'success'
) { // ) {
toast.error( // toast.error(
'Could not fetch docker hub image info. Please check image name and tag and try again' // 'Could not fetch docker hub image info. Please check image name and tag and try again'
) // )
return false // return false
} // }
return true // return true
} catch (error) { // } catch (error) {
Logger.error(error.message) // Logger.error(error.message)
toast.error( // toast.error(
'Could not fetch docker hub image info. Please check image name and tag and try again' // 'Could not fetch docker hub image info. Please check image name and tag and try again'
) // )
return false // return false
} // }
} // }
async function is3rdPartyImageValid(imageURL: string): Promise<boolean> { async function is3rdPartyImageValid(imageURL: string): Promise<boolean> {
try { try {
@ -183,55 +183,55 @@ async function is3rdPartyImageValid(imageURL: string): Promise<boolean> {
} }
} }
export async function validateDockerImage( // export async function validateDockerImage(
dockerImage: string, // dockerImage: string,
tag: string // tag: string
): Promise<boolean> { // ): Promise<boolean> {
const isValid = isUrl(dockerImage) // const isValid = isUrl(dockerImage)
? await is3rdPartyImageValid(dockerImage) // ? await is3rdPartyImageValid(dockerImage)
: await isDockerHubImageValid(dockerImage, tag) // : await isDockerHubImageValid(dockerImage, tag)
return isValid // return isValid
} // }
export function transformPublishAlgorithmFormToMetadata( // export function transformPublishAlgorithmFormToMetadata(
{ // {
name, // name,
author, // author,
description, // description,
tags, // tags,
image, // image,
containerTag, // containerTag,
entrypoint, // entrypoint,
termsAndConditions, // termsAndConditions,
files // files
}: Partial<FormPublishData>, // }: Partial<FormPublishData>,
ddo?: DDO // ddo?: DDO
): MetadataMarket { // ): MetadataMarket {
const currentTime = dateToStringNoMS(new Date()) // const currentTime = dateToStringNoMS(new Date())
const fileUrl = typeof files !== 'string' && files[0].url // const fileUrl = typeof files !== 'string' && files[0].url
const algorithmLanguage = getAlgorithmFileExtension(fileUrl) // const algorithmLanguage = getAlgorithmFileExtension(fileUrl)
const algorithm = getAlgorithmComponent( // const algorithm = getAlgorithmComponent(
image, // image,
containerTag, // containerTag,
entrypoint, // entrypoint,
algorithmLanguage // algorithmLanguage
) // )
const metadata: MetadataMarket = { // const metadata: MetadataMarket = {
main: { // main: {
name, // name,
type: 'algorithm', // type: 'algorithm',
author, // author,
dateCreated: ddo ? ddo.created : currentTime, // dateCreated: ddo ? ddo.created : currentTime,
files: typeof files !== 'string' && files, // files: typeof files !== 'string' && files,
license: 'https://market.oceanprotocol.com/terms', // license: 'https://market.oceanprotocol.com/terms',
algorithm // algorithm
}, // },
additionalInformation: { // additionalInformation: {
description, // description,
tags: transformTags(tags), // tags: transformTags(tags),
termsAndConditions // termsAndConditions
} // }
} // }
return metadata // return metadata
} // }

View File

@ -14,7 +14,7 @@ export function getOceanConfig(network: string | number): ConfigHelperConfig {
network === 'gaiaxtestnet' || network === 'gaiaxtestnet' ||
network === 2021000 network === 2021000
? undefined ? undefined
: process.env.GATSBY_INFURA_PROJECT_ID : process.env.NEXT_INFURA_PROJECT_ID
) as ConfigHelperConfig ) as ConfigHelperConfig
return config as ConfigHelperConfig return config as ConfigHelperConfig
} }

View File

@ -1,6 +1,6 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import Markdown from '@shared/atoms/Markdown' import Markdown from '@shared/Markdown'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import styles from './index.module.css' import styles from './index.module.css'

View File

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import Dotdotdot from 'react-dotdotdot' import Dotdotdot from 'react-dotdotdot'
import { Link } from 'gatsby' import Link from 'next/link'
import PriceUnit from '@shared/Price/PriceUnit' import PriceUnit from '@shared/Price/PriceUnit'
import Loader from '@shared/atoms/Loader' import Loader from '@shared/atoms/Loader'
import styles from './AssetComputeList.module.css' import styles from './AssetComputeList.module.css'
@ -24,22 +24,20 @@ export default function AssetComputeSelection({
<Empty /> <Empty />
) : ( ) : (
assets.map((asset: AssetSelectionAsset) => ( assets.map((asset: AssetSelectionAsset) => (
<Link <Link href={`/asset/${asset.did}`} key={asset.did}>
to={`/asset/${asset.did}`} <a className={styles.row}>
className={styles.row} <div className={styles.info}>
key={asset.did} <h3 className={styles.title}>
> <Dotdotdot clamp={1} tagName="span">
<div className={styles.info}> {asset.name}
<h3 className={styles.title}> </Dotdotdot>
<Dotdotdot clamp={1} tagName="span"> </h3>
{asset.name} <Dotdotdot clamp={1} tagName="code" className={styles.did}>
{asset.symbol} | {asset.did}
</Dotdotdot> </Dotdotdot>
</h3> </div>
<Dotdotdot clamp={1} tagName="code" className={styles.did}> <PriceUnit price={asset.price} small className={styles.price} />
{asset.symbol} | {asset.did} </a>
</Dotdotdot>
</div>
<PriceUnit price={asset.price} small className={styles.price} />
</Link> </Link>
)) ))
)} )}

View File

@ -1,5 +1,5 @@
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import { Link } from 'gatsby' import Link from 'next/link'
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import { getAssetsNames } from '@utils/aquarius' import { getAssetsNames } from '@utils/aquarius'
import styles from './AssetListTitle.module.css' import styles from './AssetListTitle.module.css'
@ -42,7 +42,9 @@ export default function AssetListTitle({
return ( return (
<h3 className={styles.title}> <h3 className={styles.title}>
<Link to={`/asset/${did || ddo?.id}`}>{assetTitle}</Link> <Link href={`/asset/${did || ddo?.id}`}>
<a>{assetTitle}</a>
</Link>
</h3> </h3>
) )
} }

View File

@ -4,7 +4,7 @@
} }
.link { .link {
composes: box from '../atoms/Box.module.css'; composes: box from '@shared/atoms/Box.module.css';
font-size: var(--font-size-small); font-size: var(--font-size-small);
height: 100%; height: 100%;
color: var(--color-secondary); color: var(--color-secondary);

View File

@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import { Link } from 'gatsby' import Link from 'next/link'
import Dotdotdot from 'react-dotdotdot' import Dotdotdot from 'react-dotdotdot'
import Price from '@shared/Price' import Price from '@shared/Price'
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
@ -29,38 +29,40 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({
return ( return (
<article className={`${styles.teaser} ${styles[type]}`}> <article className={`${styles.teaser} ${styles[type]}`}>
<Link to={`/asset/${ddo.id}`} className={styles.link}> <Link href={`/asset/${ddo.id}`}>
<header className={styles.header}> <a className={styles.link}>
<div className={styles.symbol}>{dataTokenInfo?.symbol}</div> <header className={styles.header}>
<Dotdotdot clamp={3}> <div className={styles.symbol}>{dataTokenInfo?.symbol}</div>
<h1 className={styles.title}>{name}</h1> <Dotdotdot clamp={3}>
</Dotdotdot> <h1 className={styles.title}>{name}</h1>
{!noPublisher && ( </Dotdotdot>
<Publisher account={owner} minimal className={styles.publisher} /> {!noPublisher && (
)} <Publisher account={owner} minimal className={styles.publisher} />
</header>
<AssetType
type={type}
accessType={accessType}
className={styles.typeDetails}
/>
<div className={styles.content}>
<Dotdotdot tagName="p" clamp={3}>
{removeMarkdown(
attributes?.additionalInformation?.description?.substring(
0,
300
) || ''
)} )}
</Dotdotdot> </header>
</div>
<footer className={styles.foot}> <AssetType
<Price price={price} small /> type={type}
<NetworkName networkId={ddo.chainId} className={styles.network} /> accessType={accessType}
</footer> className={styles.typeDetails}
/>
<div className={styles.content}>
<Dotdotdot tagName="p" clamp={3}>
{removeMarkdown(
attributes?.additionalInformation?.description?.substring(
0,
300
) || ''
)}
</Dotdotdot>
</div>
<footer className={styles.foot}>
<Price price={price} small />
<NetworkName networkId={ddo.chainId} className={styles.network} />
</footer>
</a>
</Link> </Link>
</article> </article>
) )

View File

@ -1,9 +1,9 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import styles from './index.module.css' import styles from './index.module.css'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { ReactComponent as Compute } from '@images/compute.svg' import Compute from '@images/compute.svg'
import { ReactComponent as Download } from '@images/download.svg' import Download from '@images/download.svg'
import { ReactComponent as Lock } from '@images/lock.svg' import Lock from '@images/lock.svg'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)

View File

@ -1,5 +1,5 @@
import React, { ReactElement, ReactNode, useEffect, useState } from 'react' import React, { ReactElement, ReactNode, useEffect, useState } from 'react'
import { ReactComponent as External } from '@images/external.svg' import External from '@images/external.svg'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { ConfigHelperConfig } from '@oceanprotocol/lib' import { ConfigHelperConfig } from '@oceanprotocol/lib'
import { useOcean } from '@context/Ocean' import { useOcean } from '@context/Ocean'

View File

@ -3,7 +3,7 @@ import Dotdotdot from 'react-dotdotdot'
import slugify from 'slugify' import slugify from 'slugify'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import PriceUnit from '@shared/Price/PriceUnit' import PriceUnit from '@shared/Price/PriceUnit'
import { ReactComponent as External } from '@images/external.svg' import External from '@images/external.svg'
import InputElement from '@shared/Form/Input/InputElement' import InputElement from '@shared/Form/Input/InputElement'
import Loader from '@shared/atoms/Loader' import Loader from '@shared/atoms/Loader'
import styles from './AssetSelection.module.css' import styles from './AssetSelection.module.css'

View File

@ -35,7 +35,7 @@
pointer-events: none; pointer-events: none;
} }
input[type='radio']:checked + label { .boxSelectionsWrapper input[type='radio']:checked + label {
color: var(--font-color-text); color: var(--font-color-text);
border-color: var(--color-secondary); border-color: var(--color-secondary);
} }

View File

@ -1,7 +1,7 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import styles from './RefreshName.module.css' import styles from './RefreshName.module.css'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import { ReactComponent as Refresh } from '@images/refresh.svg' import Refresh from '@images/refresh.svg'
export default function RefreshName({ export default function RefreshName({
generateName generateName

View File

@ -2,18 +2,8 @@ import React, { ReactElement } from 'react'
import { InputProps } from '@shared/Form/Input' import { InputProps } from '@shared/Form/Input'
import InputElement from '@shared/Form/Input/InputElement' import InputElement from '@shared/Form/Input/InputElement'
import styles from './Terms.module.css' import styles from './Terms.module.css'
import { graphql, useStaticQuery } from 'gatsby'
const query = graphql`
query TermsQuery {
terms: markdownRemark(fields: { slug: { eq: "/terms" } }) {
html
}
}
`
export default function Terms(props: InputProps): ReactElement { export default function Terms(props: InputProps): ReactElement {
const data = useStaticQuery(query)
const termsProps: InputProps = { const termsProps: InputProps = {
...props, ...props,
defaultChecked: props.value.toString() === 'true' defaultChecked: props.value.toString() === 'true'
@ -21,10 +11,6 @@ export default function Terms(props: InputProps): ReactElement {
return ( return (
<> <>
<div
className={styles.terms}
dangerouslySetInnerHTML={{ __html: data.terms.html }}
/>
<InputElement {...termsProps} type="checkbox" /> <InputElement {...termsProps} type="checkbox" />
</> </>
) )

View File

@ -1,6 +1,6 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import styles from './Help.module.css' import styles from './Help.module.css'
import Markdown from '@shared/atoms/Markdown' import Markdown from '@shared/Markdown'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)

View File

@ -218,17 +218,17 @@
border-color: var(--brand-grey); border-color: var(--brand-grey);
} }
input[type='range'] { .input[type='range'] {
background: transparent; background: transparent;
appearance: none; appearance: none;
} }
input[type='range']:focus { .input[type='range']:focus {
outline: none; outline: none;
} }
/* Selectors need to be split up to work in both engines */ /* Selectors need to be split up to work in both engines */
input[type='range']::-webkit-slider-thumb { .input[type='range']::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
margin-top: -0.5rem; margin-top: -0.5rem;
background: var(--brand-gradient); background: var(--brand-gradient);
@ -240,7 +240,7 @@ input[type='range']::-webkit-slider-thumb {
box-shadow: 0 2px 9px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 2px 9px 0 rgba(0, 0, 0, 0.2);
} }
input[type='range']::-moz-range-thumb { .input[type='range']::-moz-range-thumb {
background: var(--brand-gradient); background: var(--brand-gradient);
border: 2px solid var(--border-color); border: 2px solid var(--border-color);
width: var(--font-size-large); width: var(--font-size-large);
@ -250,7 +250,7 @@ input[type='range']::-moz-range-thumb {
box-shadow: 0 2px 9px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 2px 9px 0 rgba(0, 0, 0, 0.2);
} }
input[type='range']::-webkit-slider-runnable-track { .input[type='range']::-webkit-slider-runnable-track {
margin-top: -1rem; margin-top: -1rem;
background: var(--border-color); background: var(--border-color);
border-radius: var(--border-radius); border-radius: var(--border-radius);
@ -258,7 +258,7 @@ input[type='range']::-webkit-slider-runnable-track {
border: none; border: none;
} }
input[type='range']::-moz-range-track { .input[type='range']::-moz-range-track {
background: var(--border-color); background: var(--border-color);
border-radius: var(--border-radius); border-radius: var(--border-radius);
height: 0.3rem; height: 0.3rem;

View File

@ -1,5 +1,5 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import slugify from '@sindresorhus/slugify' import slugify from 'slugify'
import styles from './InputElement.module.css' import styles from './InputElement.module.css'
import { InputProps } from '.' import { InputProps } from '.'
import FilesInput from '../FormFields/FilesInput' import FilesInput from '../FormFields/FilesInput'

View File

@ -0,0 +1,24 @@
import { markdownToHtml } from '@utils/markdown'
import React, { ReactElement } from 'react'
import styles from './index.module.css'
const Markdown = ({
text,
className
}: {
text: string
className?: string
}): ReactElement => {
const content = markdownToHtml(text)
return (
<div
className={`${styles.markdown} ${className}`}
// Note: We serialize and kill all embedded HTML over in markdownToHtml()
// so the danger here is gone.
dangerouslySetInnerHTML={{ __html: content }}
/>
)
}
export default Markdown

View File

@ -1,9 +1,9 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { ReactComponent as EthIcon } from '@images/eth.svg' import EthIcon from '@images/eth.svg'
import { ReactComponent as PolygonIcon } from '@images/polygon.svg' import PolygonIcon from '@images/polygon.svg'
import { ReactComponent as MoonbeamIcon } from '@images/moonbeam.svg' import MoonbeamIcon from '@images/moonbeam.svg'
import { ReactComponent as BscIcon } from '@images/bsc.svg' import BscIcon from '@images/bsc.svg'
import { ReactComponent as EnergywebIcon } from '@images/energyweb.svg' import EnergywebIcon from '@images/energyweb.svg'
import styles from './index.module.css' import styles from './index.module.css'
export function NetworkIcon({ name }: { name: string }): ReactElement { export function NetworkIcon({ name }: { name: string }): ReactElement {

View File

@ -1,7 +1,7 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import styles from './PageHeader.module.css' import styles from './PageHeader.module.css'
import Markdown from '@shared/atoms/Markdown' import Markdown from '@shared/Markdown'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)

View File

@ -1,48 +0,0 @@
import React, { ReactElement } from 'react'
import { graphql, PageProps } from 'gatsby'
import Page from '.'
import styles from './PageMarkdown.module.css'
import Container from '@shared/atoms/Container'
import PrivacyPolicyHeader from '../../Privacy/PrivacyHeader'
export default function PageTemplateMarkdown(props: PageProps): ReactElement {
const { html, frontmatter, tableOfContents, fields } = (props.data as any)
.markdownRemark
const { title, description } = frontmatter
const { slug } = fields
const isPrivacy = slug.includes('/privacy/')
return (
<Page title={title} description={description} uri={props.uri} headerCenter>
<Container narrow>
{isPrivacy && (
<PrivacyPolicyHeader
tableOfContents={tableOfContents}
policy={slug.replace('/privacy/', '')}
/>
)}
<div
className={styles.content}
dangerouslySetInnerHTML={{ __html: html }}
/>
</Container>
</Page>
)
}
export const pageQuery = graphql`
query PageMarkdownBySlug($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
html
tableOfContents(absolute: false)
frontmatter {
title
description
}
fields {
slug
}
}
}
`

View File

@ -1,5 +1,5 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { Helmet } from 'react-helmet' import Head from 'next/head'
import { useSiteMetadata } from '@hooks/useSiteMetadata' import { useSiteMetadata } from '@hooks/useSiteMetadata'
import { isBrowser } from '@utils/index' import { isBrowser } from '@utils/index'
@ -18,13 +18,11 @@ export default function Seo({
const canonical = `${siteUrl}${uri}`.replace(/\/$/, '') const canonical = `${siteUrl}${uri}`.replace(/\/$/, '')
return ( return (
<Helmet <Head>
defaultTitle={`${siteTitle}${siteTagline}`}
titleTemplate={`%s — ${siteTitle}`}
title={title}
>
<html lang="en" /> <html lang="en" />
<title>{`${siteTitle}${siteTagline}`}</title>
{isBrowser && {isBrowser &&
window.location && window.location &&
window.location.hostname !== 'oceanprotocol.com' && ( window.location.hostname !== 'oceanprotocol.com' && (
@ -38,18 +36,12 @@ export default function Seo({
<meta property="og:description" content={description} /> <meta property="og:description" content={description} />
<meta property="og:url" content={uri} /> <meta property="og:url" content={uri} />
<meta <meta name="image" content={`${siteUrl}${siteImage}`} />
name="image" <meta property="og:image" content={`${siteUrl}${siteImage}`} />
content={`${siteUrl}${siteImage.childImageSharp.original.src}`}
/>
<meta
property="og:image"
content={`${siteUrl}${siteImage.childImageSharp.original.src}`}
/>
<meta property="og:site_name" content={siteTitle} /> <meta property="og:site_name" content={siteTitle} />
<meta name="twitter:creator" content="@oceanprotocol" /> <meta name="twitter:creator" content="@oceanprotocol" />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
</Helmet> </Head>
) )
} }

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect, ReactElement } from 'react'
import ReactPaginate from 'react-paginate' import ReactPaginate from 'react-paginate'
import styles from './index.module.css' import styles from './index.module.css'
import { MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS } from '@utils/aquarius' import { MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS } from '@utils/aquarius'
import { ReactComponent as Arrow } from '@images/arrow.svg' import Arrow from '@images/arrow.svg'
import { PaginationProps } from './_types' import { PaginationProps } from './_types'
export default function Pagination({ export default function Pagination({

View File

@ -1,5 +1,5 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { ReactComponent as External } from '@images/external.svg' import External from '@images/external.svg'
import styles from './Add.module.css' import styles from './Add.module.css'
export default function Add(): ReactElement { export default function Add(): ReactElement {

View File

@ -1,7 +1,7 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import styles from './index.module.css' import styles from './index.module.css'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { Link } from 'gatsby' import Link from 'next/link'
import get3BoxProfile from '@utils/profile' import get3BoxProfile from '@utils/profile'
import { accountTruncate } from '@utils/web3' import { accountTruncate } from '@utils/web3'
import axios from 'axios' import axios from 'axios'
@ -67,11 +67,8 @@ export default function Publisher({
name name
) : ( ) : (
<> <>
<Link <Link href={`/profile/${accountEns || account}`}>
to={`/profile/${accountEns || account}`} <a title="Show profile page.">{name}</a>
title="Show profile page."
>
{name}
</Link> </Link>
{showAdd && <Add />} {showAdd && <Add />}
</> </>

View File

@ -1,29 +1,9 @@
import React from 'react' import React, { ReactElement } from 'react'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import Loader from '@shared/atoms/Loader' import Loader from '@shared/atoms/Loader'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import Tooltip from '@shared/atoms/Tooltip' import Tooltip from '@shared/atoms/Tooltip'
import { useStaticQuery, graphql } from 'gatsby' import content from '../../../../content/price.json'
import { ReactElement } from 'react-markdown'
export const query = graphql`
query {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
edges {
node {
childContentJson {
pool {
tooltips {
approveSpecific
approveInfinite
}
}
}
}
}
}
}
`
export function ButtonApprove({ export function ButtonApprove({
amount, amount,
@ -36,10 +16,6 @@ export function ButtonApprove({
approveTokens: (amount: string) => void approveTokens: (amount: string) => void
isLoading: boolean isLoading: boolean
}): ReactElement { }): ReactElement {
// Get content
const data = useStaticQuery(query)
const content = data.content.edges[0].node.childContentJson.pool.tooltips
const { infiniteApproval } = useUserPreferences() const { infiniteApproval } = useUserPreferences()
return isLoading ? ( return isLoading ? (
@ -52,12 +28,16 @@ export function ButtonApprove({
onClick={() => approveTokens(`${2 ** 53 - 1}`)} onClick={() => approveTokens(`${2 ** 53 - 1}`)}
> >
Approve {coin}{' '} Approve {coin}{' '}
<Tooltip content={content.approveInfinite.replace('COIN', coin)} /> <Tooltip
content={content.pool.tooltips.approveInfinite.replace('COIN', coin)}
/>
</Button> </Button>
) : ( ) : (
<Button style="primary" size="small" onClick={() => approveTokens(amount)}> <Button style="primary" size="small" onClick={() => approveTokens(amount)}>
Approve {amount} {coin} Approve {amount} {coin}
<Tooltip content={content.approveSpecific.replace('COIN', coin)} /> <Tooltip
content={content.pool.tooltips.approveSpecific.replace('COIN', coin)}
/>
</Button> </Button>
) )
} }

View File

@ -25,8 +25,8 @@ export default function WalletNetworkSwitcher(): ReactElement {
async function switchWalletNetwork() { async function switchWalletNetwork() {
const networkNode = await networksList.find( const networkNode = await networksList.find(
(data) => data.node.chainId === ddo.chainId (data) => data.chainId === ddo.chainId
).node )
addCustomNetwork(web3Provider, networkNode) addCustomNetwork(web3Provider, networkNode)
} }

View File

@ -2,7 +2,7 @@ import React, { ReactElement, FormEvent } from 'react'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import styles from './Alert.module.css' import styles from './Alert.module.css'
import Button from './Button' import Button from './Button'
import Markdown from './Markdown' import Markdown from '../Markdown'
import Badge from './Badge' import Badge from './Badge'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)

View File

@ -1,5 +1,5 @@
import React, { ReactNode, FormEvent, ReactElement } from 'react' import React, { ReactNode, FormEvent, ReactElement } from 'react'
import { Link } from 'gatsby' import Link from 'next/link'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import styles from './Button.module.css' import styles from './Button.module.css'
@ -41,8 +41,10 @@ export default function Button({
}) })
return to ? ( return to ? (
<Link to={to} className={styleClasses} {...props}> <Link href={to}>
{children} <a className={styleClasses} {...props}>
{children}
</a>
</Link> </Link>
) : href ? ( ) : href ? (
<a href={href} className={styleClasses} {...props}> <a href={href} className={styleClasses} {...props}>

View File

@ -1,7 +1,7 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import loadable from '@loadable/component' import loadable from '@loadable/component'
import styles from './Copy.module.css' import styles from './Copy.module.css'
import { ReactComponent as IconCopy } from '@images/copy.svg' import IconCopy from '@images/copy.svg'
// lazy load when needed only, as library is a bit big // lazy load when needed only, as library is a bit big
const Clipboard = loadable(() => import('react-clipboard.js')) const Clipboard = loadable(() => import('react-clipboard.js'))

View File

@ -1,6 +1,6 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { ReactComponent as LogoAssetFull } from '@oceanprotocol/art/logo/logo.svg' import LogoAssetFull from '@oceanprotocol/art/logo/logo.svg'
import { ReactComponent as LogoAsset } from '@images/logo.svg' import LogoAsset from '@images/logo.svg'
import styles from './Logo.module.css' import styles from './Logo.module.css'
export default function Logo({ export default function Logo({

View File

@ -1,22 +0,0 @@
import React, { ReactElement } from 'react'
import ReactMarkdown from 'react-markdown'
import styles from './Markdown.module.css'
const Markdown = ({
text,
className
}: {
text: string
className?: string
}): ReactElement => {
// fix react-markdown \n transformation
// https://github.com/rexxars/react-markdown/issues/105#issuecomment-351585313
const textCleaned = text?.replace(/\\n/g, '\n ')
return (
<ReactMarkdown className={`${styles.markdown} ${className}`}>
{textCleaned}
</ReactMarkdown>
)
}
export default Markdown

View File

@ -1,8 +1,3 @@
/* prevent background scrolling */
:global(.ReactModal__Body--open) {
overflow: hidden;
}
.modalOverlay { .modalOverlay {
position: fixed; position: fixed;
top: 0; top: 0;

View File

@ -2,7 +2,7 @@ import React, { ReactElement, ReactNode } from 'react'
import ReactModal from 'react-modal' import ReactModal from 'react-modal'
import styles from './Modal.module.css' import styles from './Modal.module.css'
if (process.env.NODE_ENV !== 'test') ReactModal.setAppElement('#___gatsby') if (process.env.NODE_ENV !== 'test') ReactModal.setAppElement('#__next')
export interface ModalProps extends ReactModal.Props { export interface ModalProps extends ReactModal.Props {
title: string title: string

View File

@ -61,7 +61,7 @@
display: none; display: none;
} }
div [class*='Table-module'] { .table [class*='Table-module'] {
scrollbar-width: thin; scrollbar-width: thin;
} }

View File

@ -1,6 +1,5 @@
import React from 'react' import React from 'react'
import { Link } from 'gatsby' import Link from 'next/link'
import shortid from 'shortid'
import styles from './Tags.module.css' import styles from './Tags.module.css'
declare type TagsProps = { declare type TagsProps = {
@ -16,12 +15,10 @@ const Tag = ({ tag, noLinks }: { tag: string; noLinks?: boolean }) => {
return noLinks ? ( return noLinks ? (
<span className={styles.tag}>{tag}</span> <span className={styles.tag}>{tag}</span>
) : ( ) : (
<Link <Link href={`/search?tags=${urlEncodedTag}&sort=created&sortOrder=desc`}>
to={`/search?tags=${urlEncodedTag}&sort=created&sortOrder=desc`} <a className={styles.tag} title={tag}>
className={styles.tag} {tag}
title={tag} </a>
>
{tag}
</Link> </Link>
) )
} }
@ -43,7 +40,7 @@ const Tags: React.FC<TagsProps> = ({
return ( return (
<div className={classes}> <div className={classes}>
{tags?.map((tag) => ( {tags?.map((tag) => (
<Tag tag={tag} noLinks={noLinks} key={shortid.generate()} /> <Tag tag={tag} noLinks={noLinks} key={tag} />
))} ))}
{shouldShowMore && ( {shouldShowMore && (
<span className={styles.more}>{`+ ${items.length - max} more`}</span> <span className={styles.more}>{`+ ${items.length - max} more`}</span>

View File

@ -3,7 +3,7 @@ import classNames from 'classnames/bind'
import loadable from '@loadable/component' import loadable from '@loadable/component'
import { useSpring, animated } from 'react-spring' import { useSpring, animated } from 'react-spring'
import styles from './Tooltip.module.css' import styles from './Tooltip.module.css'
import { ReactComponent as Info } from '@images/info.svg' import Info from '@images/info.svg'
import { Placement } from 'tippy.js' import { Placement } from 'tippy.js'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)

View File

@ -1,6 +1,7 @@
.app { .app {
height: 100%; height: 100%;
background: url('@oceanprotocol/art/waves/waves.svg') no-repeat center 13.5rem; background: url('../../../node_modules/@oceanprotocol/art/waves/waves.svg')
no-repeat center 13.5rem;
/* sticky footer technique */ /* sticky footer technique */
display: flex; display: flex;

View File

@ -1,69 +1,50 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { graphql, PageProps, useStaticQuery } from 'gatsby'
import Alert from '@shared/atoms/Alert' import Alert from '@shared/atoms/Alert'
import Footer from '../Footer/Footer' import Footer from '../Footer/Footer'
import Header from '../Header' import Header from '../Header'
import StylesGlobal from '../../stylesGlobal/StylesGlobal'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { useSiteMetadata } from '@hooks/useSiteMetadata' import { useSiteMetadata } from '@hooks/useSiteMetadata'
import { useAccountPurgatory } from '@hooks/useAccountPurgatory' import { useAccountPurgatory } from '@hooks/useAccountPurgatory'
import AnnouncementBanner from '@shared/AnnouncementBanner' import AnnouncementBanner from '@shared/AnnouncementBanner'
import PrivacyPreferenceCenter from '../Privacy/PrivacyPreferenceCenter' import PrivacyPreferenceCenter from '../Privacy/PrivacyPreferenceCenter'
import styles from './index.module.css' import styles from './index.module.css'
import { ToastContainer } from 'react-toastify'
const contentQuery = graphql` import { useRouter } from 'next/router'
query AppQuery { // import waves from '@oceanprotocol/art/waves/waves.png'
purgatory: allFile(filter: { relativePath: { eq: "purgatory.json" } }) { import content from '../../../content/purgatory.json'
edges {
node {
childContentJson {
account {
title
description
}
}
}
}
}
}
`
export default function App({ export default function App({
children, children
...props
}: { }: {
children: ReactElement children: ReactElement
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery) const router = useRouter()
const purgatory = data.purgatory.edges[0].node.childContentJson.account
const { warning, appConfig } = useSiteMetadata() const { warning, appConfig } = useSiteMetadata()
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId) const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
return ( return (
<StylesGlobal> <div className={styles.app}>
<div className={styles.app}> {router.pathname === '/' && <AnnouncementBanner text={warning.main} />}
{(props as PageProps).uri === '/' && ( <Header />
<AnnouncementBanner text={warning.main} />
)}
<Header />
{isInPurgatory && ( {isInPurgatory && (
<Alert <Alert
title={purgatory.title} title={content.account.title}
badge={`Reason: ${purgatoryData?.reason}`} badge={`Reason: ${purgatoryData?.reason}`}
text={purgatory.description} text={content.account.description}
state="error" state="error"
/> />
)} )}
<main className={styles.main}>{children}</main> <main className={styles.main}>{children}</main>
<Footer /> <Footer />
{appConfig.privacyPreferenceCenter === 'true' && ( {appConfig.privacyPreferenceCenter === 'true' && (
<PrivacyPreferenceCenter style="small" /> <PrivacyPreferenceCenter style="small" />
)} )}
</div>
</StylesGlobal> <ToastContainer position="bottom-right" newestOnTop />
</div>
) )
} }

View File

@ -1,14 +0,0 @@
import { PageProps } from 'gatsby'
import React, { ReactElement } from 'react'
import App from '.'
// Gatsby-specific, referenced in gatsby-browser.js & gatsby-ssr.js
const wrapPageElement = ({
element,
props
}: {
element: ReactElement
props: PageProps
}): ReactElement => <App {...props}>{element}</App>
export default wrapPageElement

View File

@ -1,8 +1,7 @@
import React, { ReactElement, useState } from 'react' import React, { ReactElement, ReactNode, useState } from 'react'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import styles from './AssetActionHistoryTable.module.css' import styles from './AssetActionHistoryTable.module.css'
import { ReactComponent as Caret } from '@images/caret.svg' import Caret from '@images/caret.svg'
import { ReactNode } from 'react-markdown'
export default function AssetActionHistoryTable({ export default function AssetActionHistoryTable({
title, title,

View File

@ -2,7 +2,6 @@ import React, { ReactElement, useEffect, useState } from 'react'
import styles from './FormComputeDataset.module.css' import styles from './FormComputeDataset.module.css'
import { Field, Form, FormikContextType, useFormikContext } from 'formik' import { Field, Form, FormikContextType, useFormikContext } from 'formik'
import Input from '@shared/Form/Input' import Input from '@shared/Form/Input'
import { useStaticQuery, graphql } from 'gatsby'
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import { AssetSelectionAsset } from '@shared/Form/FormFields/AssetSelection' import { AssetSelectionAsset } from '@shared/Form/FormFields/AssetSelection'
import { compareAsBN } from '@utils/numbers' import { compareAsBN } from '@utils/numbers'
@ -11,36 +10,7 @@ import PriceOutput from './PriceOutput'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useOcean } from '@context/Ocean' import { useOcean } from '@context/Ocean'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import content from '../../../../../content/pages/startComputeDataset.json'
const contentQuery = graphql`
query StartComputeDatasetQuery {
content: allFile(
filter: { relativePath: { eq: "pages/startComputeDataset.json" } }
) {
edges {
node {
childPagesJson {
description
form {
success
successAction
error
data {
name
label
help
type
required
sortOptions
options
}
}
}
}
}
}
}
`
export default function FormStartCompute({ export default function FormStartCompute({
algorithms, algorithms,
@ -91,9 +61,6 @@ export default function FormStartCompute({
isConsumable: boolean isConsumable: boolean
consumableFeedback: string consumableFeedback: string
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childPagesJson
const { isValid, values }: FormikContextType<{ algorithm: string }> = const { isValid, values }: FormikContextType<{ algorithm: string }> =
useFormikContext() useFormikContext()
const { price, ddo, isAssetNetwork } = useAsset() const { price, ddo, isAssetNetwork } = useAsset()

View File

@ -1,31 +1,31 @@
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import React, { ReactElement } from 'react' // import React, { ReactElement } from 'react'
import { transformPublishFormToMetadata } from '@utils/metadata' // import { transformPublishFormToMetadata } from '@utils/metadata'
import DebugOutput from '@shared/DebugOutput' // import DebugOutput from '@shared/DebugOutput'
import { FormPublishData } from '../../../Publish/_types' // import { FormPublishData } from '../../../Publish/_types'
export default function Debug({ // export default function Debug({
values, // values,
ddo // ddo
}: { // }: {
values: Partial<FormPublishData> // values: Partial<FormPublishData>
ddo: DDO // ddo: DDO
}): ReactElement { // }): ReactElement {
const newDdo = { // const newDdo = {
'@context': 'https://w3id.org/did/v1', // '@context': 'https://w3id.org/did/v1',
service: [ // service: [
{ // {
index: 0, // index: 0,
type: 'metadata', // type: 'metadata',
attributes: { ...transformPublishFormToMetadata(values, ddo) } // attributes: { ...transformPublishFormToMetadata(values, ddo) }
} // }
] // ]
} // }
return ( // return (
<> // <>
<DebugOutput title="Collected Form Values" output={values} /> // <DebugOutput title="Collected Form Values" output={values} />
<DebugOutput title="Transformed DDO Values" output={newDdo} /> // <DebugOutput title="Transformed DDO Values" output={newDdo} />
</> // </>
) // )
} // }

View File

@ -5,7 +5,6 @@ import React, { ReactElement, useState } from 'react'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import FormEditComputeDataset from './FormEditComputeDataset' import FormEditComputeDataset from './FormEditComputeDataset'
import { Logger, ServiceComputePrivacy } from '@oceanprotocol/lib' import { Logger, ServiceComputePrivacy } from '@oceanprotocol/lib'
import { graphql, useStaticQuery } from 'gatsby'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import DebugEditCompute from './DebugEditCompute' import DebugEditCompute from './DebugEditCompute'
import styles from './index.module.css' import styles from './index.module.css'
@ -14,49 +13,13 @@ import { setMinterToDispenser, setMinterToPublisher } from '@utils/freePrice'
import Web3Feedback from '@shared/Web3Feedback' import Web3Feedback from '@shared/Web3Feedback'
import MetadataFeedback from '../../../Publish/MetadataFeedback' import MetadataFeedback from '../../../Publish/MetadataFeedback'
import { getInitialValues, validationSchema } from './_constants' import { getInitialValues, validationSchema } from './_constants'
import content from '../../../../../content/pages/editComputeDataset.json'
const contentQuery = graphql`
query EditComputeDataQuery {
content: allFile(
filter: { relativePath: { eq: "pages/editComputeDataset.json" } }
) {
edges {
node {
childPagesJson {
description
form {
title
success
successAction
error
data {
name
placeholder
label
help
type
required
sortOptions
options
multiple
rows
}
}
}
}
}
}
}
`
export default function EditComputeDataset({ export default function EditComputeDataset({
setShowEdit setShowEdit
}: { }: {
setShowEdit: (show: boolean) => void setShowEdit: (show: boolean) => void
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childPagesJson
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { ocean } = useOcean() const { ocean } = useOcean()
const { accountId } = useWeb3() const { accountId } = useWeb3()
@ -127,15 +90,18 @@ export default function EditComputeDataset({
return ( return (
<Formik <Formik
initialValues={getInitialValues( initialValues={
ddo.findServiceByType('compute').attributes.main.privacy {}
)} // getInitialValues(
// ddo.findServiceByType('compute').attributes.main.privacy
// )
}
validationSchema={validationSchema} validationSchema={validationSchema}
onSubmit={async (values, { resetForm }) => { onSubmit={async (values, { resetForm }) => {
// move user's focus to top of screen // move user's focus to top of screen
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
// kick off editing // kick off editing
await handleSubmit(values, resetForm) // await handleSubmit(values, resetForm)
}} }}
> >
{({ values, isSubmitting }) => {({ values, isSubmitting }) =>
@ -166,7 +132,7 @@ export default function EditComputeDataset({
<Web3Feedback isAssetNetwork={isAssetNetwork} /> <Web3Feedback isAssetNetwork={isAssetNetwork} />
{debug === true && ( {debug === true && (
<div className={styles.grid}> <div className={styles.grid}>
<DebugEditCompute values={values} ddo={ddo} /> {/* <DebugEditCompute values={values} ddo={ddo} /> */}
</div> </div>
)} )}
</> </>

View File

@ -7,39 +7,39 @@ import FormActions from './FormActions'
import styles from './FormEditMetadata.module.css' import styles from './FormEditMetadata.module.css'
import { FormPublishData } from '../../../Publish/_types' import { FormPublishData } from '../../../Publish/_types'
function handleTimeoutCustomOption( // function handleTimeoutCustomOption(
data: FormFieldProps[], // data: FormFieldProps[],
values: Partial<FormPublishData> // values: Partial<FormPublishData>
) { // ) {
const timeoutFieldContent = data.filter( // const timeoutFieldContent = data.filter(
(field) => field.name === 'timeout' // (field) => field.name === 'timeout'
)[0] // )[0]
const timeoutInputIndex = data.findIndex( // const timeoutInputIndex = data.findIndex(
(element) => element.name === 'timeout' // (element) => element.name === 'timeout'
) // )
if ( // if (
data[timeoutInputIndex].options.length < 6 && // data[timeoutInputIndex].options.length < 6 &&
!checkIfTimeoutInPredefinedValues( // !checkIfTimeoutInPredefinedValues(
values.timeout, // values.timeout,
timeoutFieldContent.options // timeoutFieldContent.options
) // )
) { // ) {
data[timeoutInputIndex].options.push(values.timeout) // data[timeoutInputIndex].options.push(values.timeout)
} else if ( // } else if (
data[timeoutInputIndex].options.length === 6 && // data[timeoutInputIndex].options.length === 6 &&
checkIfTimeoutInPredefinedValues( // checkIfTimeoutInPredefinedValues(
values.timeout, // values.timeout,
timeoutFieldContent.options // timeoutFieldContent.options
) // )
) { // ) {
data[timeoutInputIndex].options.pop() // data[timeoutInputIndex].options.pop()
} else if ( // } else if (
data[timeoutInputIndex].options.length === 6 && // data[timeoutInputIndex].options.length === 6 &&
data[timeoutInputIndex].options[5] !== values.timeout // data[timeoutInputIndex].options[5] !== values.timeout
) { // ) {
data[timeoutInputIndex].options[5] = values.timeout // data[timeoutInputIndex].options[5] = values.timeout
} // }
} // }
export default function FormEditMetadata({ export default function FormEditMetadata({
data, data,
setShowEdit, setShowEdit,
@ -73,18 +73,18 @@ export default function FormEditMetadata({
// This component is handled by Formik so it's not rendered like a "normal" react component, // This component is handled by Formik so it's not rendered like a "normal" react component,
// so handleTimeoutCustomOption is called only once. // so handleTimeoutCustomOption is called only once.
// https://github.com/oceanprotocol/market/pull/324#discussion_r561132310 // https://github.com/oceanprotocol/market/pull/324#discussion_r561132310
if (data && values) handleTimeoutCustomOption(data, values) // if (data && values) handleTimeoutCustomOption(data, values)
const timeoutOptionsArray = data.filter( const timeoutOptionsArray = data.filter(
(field) => field.name === 'timeout' (field) => field.name === 'timeout'
)[0].options )[0].options
if (isComputeDataset && timeoutOptionsArray.includes('Forever')) { // if (isComputeDataset && timeoutOptionsArray.includes('Forever')) {
const foreverOptionIndex = timeoutOptionsArray.indexOf('Forever') // const foreverOptionIndex = timeoutOptionsArray.indexOf('Forever')
timeoutOptionsArray.splice(foreverOptionIndex, 1) // timeoutOptionsArray.splice(foreverOptionIndex, 1)
} else if (!isComputeDataset && !timeoutOptionsArray.includes('Forever')) { // } else if (!isComputeDataset && !timeoutOptionsArray.includes('Forever')) {
timeoutOptionsArray.push('Forever') // timeoutOptionsArray.push('Forever')
} // }
return ( return (
<Form className={styles.form}> <Form className={styles.form}>
@ -108,10 +108,10 @@ export default function FormEditMetadata({
) )
)} )}
<FormActions {/* <FormActions
setShowEdit={setShowEdit} setShowEdit={setShowEdit}
handleClick={() => setTimeoutStringValue(values.timeout)} handleClick={() => setTimeoutStringValue(values.timeout)}
/> /> */}
</Form> </Form>
) )
} }

View File

@ -22,7 +22,6 @@ export function getInitialValues(
name: metadata.main.name, name: metadata.main.name,
description: metadata.additionalInformation.description, description: metadata.additionalInformation.description,
price, price,
links: metadata.additionalInformation.links,
timeout: secondsToString(timeout), timeout: secondsToString(timeout),
author: metadata.main.author author: metadata.main.author
} }

View File

@ -3,49 +3,18 @@ import React, { ReactElement, useState } from 'react'
import { validationSchema, getInitialValues } from './_constants' import { validationSchema, getInitialValues } from './_constants'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import Debug from './DebugEditMetadata' // import Debug from './DebugEditMetadata'
import Web3Feedback from '@shared/Web3Feedback' import Web3Feedback from '@shared/Web3Feedback'
import FormEditMetadata from './FormEditMetadata' import FormEditMetadata from './FormEditMetadata'
import { mapTimeoutStringToSeconds } from '@utils/metadata' import { mapTimeoutStringToSeconds } from '@utils/metadata'
import styles from './index.module.css' import styles from './index.module.css'
import { Logger } from '@oceanprotocol/lib' import { Logger } from '@oceanprotocol/lib'
import { graphql, useStaticQuery } from 'gatsby'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { useOcean } from '@context/Ocean' import { useOcean } from '@context/Ocean'
import { setMinterToDispenser, setMinterToPublisher } from '@utils/freePrice' import { setMinterToDispenser, setMinterToPublisher } from '@utils/freePrice'
import { MetadataPreview } from '../../../Publish/MetadataPreview' import { MetadataPreview } from '../../../Publish/MetadataPreview'
import MetadataFeedback from '../../../Publish/MetadataFeedback' import MetadataFeedback from '../../../Publish/MetadataFeedback'
import content from '../../../../../content/pages/edit.json'
const contentQuery = graphql`
query EditMetadataQuery {
content: allFile(filter: { relativePath: { eq: "pages/edit.json" } }) {
edges {
node {
childPagesJson {
description
form {
success
successAction
error
data {
name
placeholder
label
help
type
min
required
sortOptions
options
rows
}
}
}
}
}
}
}
`
export default function Edit({ export default function Edit({
setShowEdit, setShowEdit,
@ -54,9 +23,6 @@ export default function Edit({
setShowEdit: (show: boolean) => void setShowEdit: (show: boolean) => void
isComputeType?: boolean isComputeType?: boolean
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childPagesJson
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { ocean } = useOcean() const { ocean } = useOcean()
@ -190,21 +156,21 @@ export default function Edit({
<> <>
<p className={styles.description}>{content.description}</p> <p className={styles.description}>{content.description}</p>
<article className={styles.grid}> <article className={styles.grid}>
<FormEditMetadata {/* <FormEditMetadata
data={content.form.data} data={content.form.data}
setShowEdit={setShowEdit} setShowEdit={setShowEdit}
setTimeoutStringValue={setTimeoutStringValue} setTimeoutStringValue={setTimeoutStringValue}
values={initialValues} // values={initialValues}
showPrice={price.type === 'exchange'} showPrice={price.type === 'exchange'}
isComputeDataset={isComputeType} isComputeDataset={isComputeType}
/> /> */}
<aside> <aside>
<MetadataPreview values={values} /> {/* <MetadataPreview values={values} /> */}
<Web3Feedback /> <Web3Feedback />
</aside> </aside>
{debug === true && <Debug values={values} ddo={ddo} />} {/* {debug === true && <Debug values={values} ddo={ddo} />} */}
</article> </article>
</> </>
) )

View File

@ -1,33 +1,11 @@
import { FormikContextType, useFormikContext } from 'formik' import { FormikContextType, useFormikContext } from 'formik'
import { graphql, useStaticQuery } from 'gatsby'
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import { FormAddLiquidity } from '.' import { FormAddLiquidity } from '.'
import FormHelp from '@shared/Form/Input/Help' import FormHelp from '@shared/Form/Input/Help'
import Token from '../Token' import Token from '../Token'
import styles from './Output.module.css' import styles from './Output.module.css'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import content from '../../../../../../content/price.json'
const contentQuery = graphql`
query PoolAddOutputQuery {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
edges {
node {
childContentJson {
pool {
add {
output {
help
titleIn
titleOut
}
}
}
}
}
}
}
}
`
export default function Output({ export default function Output({
newPoolTokens, newPoolTokens,
@ -46,9 +24,7 @@ export default function Output({
totalBalance: PoolBalance totalBalance: PoolBalance
coin: string coin: string
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery) const { help, titleIn, titleOut } = content.pool.add.output
const { help, titleIn, titleOut } =
data.content.edges[0].node.childContentJson.pool.add.output
// Connect with form // Connect with form
const { values }: FormikContextType<FormAddLiquidity> = useFormikContext() const { values }: FormikContextType<FormAddLiquidity> = useFormikContext()

View File

@ -2,7 +2,6 @@ import React, { ReactElement, useState, useEffect } from 'react'
import Header from '../Header' import Header from '../Header'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import Actions from '../Actions' import Actions from '../Actions'
import { graphql, useStaticQuery } from 'gatsby'
import * as Yup from 'yup' import * as Yup from 'yup'
import { Formik } from 'formik' import { Formik } from 'formik'
import FormAdd from './FormAdd' import FormAdd from './FormAdd'
@ -14,26 +13,7 @@ import DebugOutput from '@shared/DebugOutput'
import { useOcean } from '@context/Ocean' import { useOcean } from '@context/Ocean'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import content from '../../../../../../content/price.json'
const contentQuery = graphql`
query PoolAddQuery {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
edges {
node {
childContentJson {
pool {
add {
title
action
warning
}
}
}
}
}
}
}
`
export interface FormAddLiquidity { export interface FormAddLiquidity {
amount: number amount: number
@ -62,9 +42,6 @@ export default function Add({
dtSymbol: string dtSymbol: string
dtAddress: string dtAddress: string
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childContentJson.pool.add
const { accountId, balance } = useWeb3() const { accountId, balance } = useWeb3()
const { ocean } = useOcean() const { ocean } = useOcean()
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
@ -147,7 +124,10 @@ export default function Add({
return ( return (
<> <>
<Header title={content.title} backAction={() => setShowAdd(false)} /> <Header
title={content.pool.add.title}
backAction={() => setShowAdd(false)}
/>
<Formik <Formik
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={validationSchema}
@ -174,10 +154,10 @@ export default function Add({
setNewPoolShare={setNewPoolShare} setNewPoolShare={setNewPoolShare}
/> />
) : ( ) : (
content.warning && ( content.pool.add.warning && (
<Alert <Alert
className={styles.warning} className={styles.warning}
text={content.warning.toString()} text={content.pool.add.warning.toString()}
state="info" state="info"
action={{ action={{
name: 'I understand', name: 'I understand',
@ -209,7 +189,7 @@ export default function Add({
isLoading={isSubmitting} isLoading={isSubmitting}
loaderMessage="Adding Liquidity..." loaderMessage="Adding Liquidity..."
successMessage="Successfully added liquidity." successMessage="Successfully added liquidity."
actionName={content.action} actionName={content.pool.add.action}
action={submitForm} action={submitForm}
amount={amount} amount={amount}
coin={coin} coin={coin}

View File

@ -15,7 +15,6 @@ import Token from './Token'
import FormHelp from '@shared/Form/Input/Help' import FormHelp from '@shared/Form/Input/Help'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import { getMaxPercentRemove } from './utils' import { getMaxPercentRemove } from './utils'
import { graphql, useStaticQuery } from 'gatsby'
import debounce from 'lodash.debounce' import debounce from 'lodash.debounce'
import UserLiquidity from '../UserLiquidity' import UserLiquidity from '../UserLiquidity'
import InputElement from '@shared/Form/Input/InputElement' import InputElement from '@shared/Form/Input/InputElement'
@ -23,31 +22,7 @@ import { useOcean } from '@context/Ocean'
import { useWeb3 } from '@context/Web3' import { useWeb3 } from '@context/Web3'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import content from '../../../../../content/price.json'
const contentQuery = graphql`
query PoolRemoveQuery {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
edges {
node {
childContentJson {
pool {
remove {
title
simple
advanced
output {
titleIn
titleOut
}
action
}
}
}
}
}
}
}
`
export default function Remove({ export default function Remove({
setShowRemove, setShowRemove,
@ -64,9 +39,6 @@ export default function Remove({
totalPoolTokens: string totalPoolTokens: string
dtSymbol: string dtSymbol: string
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childContentJson.pool.remove
const slippagePresets = ['5', '10', '15', '25', '50'] const slippagePresets = ['5', '10', '15', '25', '50']
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { ocean } = useOcean() const { ocean } = useOcean()
@ -222,7 +194,10 @@ export default function Remove({
return ( return (
<div className={styles.remove}> <div className={styles.remove}>
<Header title={content.title} backAction={() => setShowRemove(false)} /> <Header
title={content.pool.remove.title}
backAction={() => setShowRemove(false)}
/>
<form className={styles.removeInput}> <form className={styles.removeInput}>
<UserLiquidity amount={poolTokens} symbol="pool shares" /> <UserLiquidity amount={poolTokens} symbol="pool shares" />
@ -249,7 +224,9 @@ export default function Remove({
</div> </div>
<FormHelp> <FormHelp>
{isAdvanced === true ? content.advanced : content.simple} {isAdvanced === true
? content.pool.remove.advanced
: content.pool.remove.simple}
</FormHelp> </FormHelp>
<Button <Button
style="text" style="text"
@ -264,11 +241,11 @@ export default function Remove({
</form> </form>
<div className={styles.output}> <div className={styles.output}>
<div> <div>
<p>{content.output.titleIn}</p> <p>{content.pool.remove.output.titleIn}</p>
<Token symbol="pool shares" balance={amountPoolShares} noIcon /> <Token symbol="pool shares" balance={amountPoolShares} noIcon />
</div> </div>
<div> <div>
<p>{content.output.titleOut} minimum</p> <p>{content.pool.remove.output.titleOut} minimum</p>
{isAdvanced === true ? ( {isAdvanced === true ? (
<> <>
<Token symbol="OCEAN" balance={minOceanAmount} /> <Token symbol="OCEAN" balance={minOceanAmount} />
@ -296,7 +273,7 @@ export default function Remove({
<Actions <Actions
isLoading={isLoading} isLoading={isLoading}
loaderMessage="Removing Liquidity..." loaderMessage="Removing Liquidity..."
actionName={content.action} actionName={content.pool.remove.action}
action={handleRemoveLiquidity} action={handleRemoveLiquidity}
successMessage="Successfully removed liquidity." successMessage="Successfully removed liquidity."
isDisabled={!isAssetNetwork} isDisabled={!isAssetNetwork}

View File

@ -10,7 +10,6 @@ import Tooltip from '@shared/atoms/Tooltip'
import ExplorerLink from '@shared/ExplorerLink' import ExplorerLink from '@shared/ExplorerLink'
import Token from './Token' import Token from './Token'
import TokenList from './TokenList' import TokenList from './TokenList'
import { graphql, useStaticQuery } from 'gatsby'
import AssetActionHistoryTable from '../AssetActionHistoryTable' import AssetActionHistoryTable from '../AssetActionHistoryTable'
import Graph from './Graph' import Graph from './Graph'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
@ -21,29 +20,12 @@ import PoolTransactions from '@shared/PoolTransactions'
import { fetchData, getQueryContext } from '@utils/subgraph' import { fetchData, getQueryContext } from '@utils/subgraph'
import { isValidNumber } from '@utils/numbers' import { isValidNumber } from '@utils/numbers'
import Decimal from 'decimal.js' import Decimal from 'decimal.js'
import content from '../../../../../content/price.json'
const REFETCH_INTERVAL = 5000 const REFETCH_INTERVAL = 5000
Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 }) Decimal.set({ toExpNeg: -18, precision: 18, rounding: 1 })
const contentQuery = graphql`
query PoolQuery {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
edges {
node {
childContentJson {
pool {
tooltips {
price
liquidity
}
}
}
}
}
}
}
`
const poolLiquidityQuery = gql` const poolLiquidityQuery = gql`
query PoolLiquidity($id: ID!, $shareId: ID) { query PoolLiquidity($id: ID!, $shareId: ID) {
pool(id: $id) { pool(id: $id) {
@ -79,9 +61,6 @@ const userPoolShareQuery = gql`
` `
export default function Pool(): ReactElement { export default function Pool(): ReactElement {
const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childContentJson.pool
const { accountId } = useWeb3() const { accountId } = useWeb3()
const [dtSymbol, setDtSymbol] = useState<string>() const [dtSymbol, setDtSymbol] = useState<string>()
const [oceanSymbol, setOceanSymbol] = useState<string>() const [oceanSymbol, setOceanSymbol] = useState<string>()
@ -397,7 +376,7 @@ export default function Pool(): ReactElement {
<div className={styles.dataToken}> <div className={styles.dataToken}>
<PriceUnit price="1" symbol={dtSymbol} /> ={' '} <PriceUnit price="1" symbol={dtSymbol} /> ={' '}
<PriceUnit price={`${price?.value}`} symbol={oceanSymbol} /> <PriceUnit price={`${price?.value}`} symbol={oceanSymbol} />
<Tooltip content={content.tooltips.price} /> <Tooltip content={content.pool.tooltips.price} />
<div className={styles.dataTokenLinks}> <div className={styles.dataTokenLinks}>
<ExplorerLink <ExplorerLink
networkId={ddo.chainId} networkId={ddo.chainId}
@ -423,7 +402,7 @@ export default function Pool(): ReactElement {
<> <>
Your Liquidity Your Liquidity
<Tooltip <Tooltip
content={content.tooltips.liquidity.replace( content={content.pool.tooltips.liquidity.replace(
'SWAPFEE', 'SWAPFEE',
swapFee swapFee
)} )}

View File

@ -3,7 +3,6 @@ import { DDO, Logger } from '@oceanprotocol/lib'
import * as Yup from 'yup' import * as Yup from 'yup'
import { Formik } from 'formik' import { Formik } from 'formik'
import Actions from '../Pool/Actions' import Actions from '../Pool/Actions'
import { graphql, useStaticQuery } from 'gatsby'
import { useUserPreferences } from '@context/UserPreferences' import { useUserPreferences } from '@context/UserPreferences'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import Swap from './Swap' import Swap from './Swap'
@ -15,23 +14,7 @@ import { useWeb3 } from '@context/Web3'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { FormTradeData } from './_types' import { FormTradeData } from './_types'
import { initialValues } from './_constants' import { initialValues } from './_constants'
import content from '../../../../../content/price.json'
const contentQuery = graphql`
query TradeQuery {
content: allFile(filter: { relativePath: { eq: "price.json" } }) {
edges {
node {
childContentJson {
trade {
action
warning
}
}
}
}
}
}
`
export default function FormTrade({ export default function FormTrade({
ddo, ddo,
@ -46,8 +29,6 @@ export default function FormTrade({
maxOcean: string maxOcean: string
price: BestPrice price: BestPrice
}): ReactElement { }): ReactElement {
const data = useStaticQuery(contentQuery)
const content = data.content.edges[0].node.childContentJson.trade
const { accountId } = useWeb3() const { accountId } = useWeb3()
const { ocean } = useOcean() const { ocean } = useOcean()
const { isAssetNetwork } = useAsset() const { isAssetNetwork } = useAsset()
@ -141,7 +122,7 @@ export default function FormTrade({
) : ( ) : (
<div className={styles.alertWrap}> <div className={styles.alertWrap}>
<Alert <Alert
text={content.warning} text={content.trade.warning}
state="info" state="info"
action={{ action={{
name: 'I understand', name: 'I understand',
@ -162,7 +143,7 @@ export default function FormTrade({
isLoading={isSubmitting} isLoading={isSubmitting}
loaderMessage="Swapping tokens..." loaderMessage="Swapping tokens..."
successMessage="Successfully swapped tokens." successMessage="Successfully swapped tokens."
actionName={content.action} actionName={content.trade.action}
amount={ amount={
values.type === 'sell' values.type === 'sell'
? values.datatoken ? values.datatoken

View File

@ -3,7 +3,7 @@ import { DDO } from '@oceanprotocol/lib'
import styles from './Swap.module.css' import styles from './Swap.module.css'
import TradeInput from './TradeInput' import TradeInput from './TradeInput'
import Button from '@shared/atoms/Button' import Button from '@shared/atoms/Button'
import { ReactComponent as Arrow } from '@images/arrow.svg' import Arrow from '@images/arrow.svg'
import { FormikContextType, useFormikContext } from 'formik' import { FormikContextType, useFormikContext } from 'formik'
import { useOcean } from '@context/Ocean' import { useOcean } from '@context/Ocean'
import Output from './Output' import Output from './Output'

Some files were not shown because too many files have changed in this diff Show More