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

Merge branch 'main' into feature/issue-1244-edit-ui-highlights-clear

This commit is contained in:
EnzoVezzaro 2023-02-03 10:47:58 -04:00 committed by GitHub
commit a0c8c730cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 201 additions and 93 deletions

View File

@ -120,6 +120,20 @@
"placeholder": "e.g. 0X123ABC...", "placeholder": "e.g. 0X123ABC...",
"help": "This address will receive the revenue from all sales. More info available in our [docs](https://docs.oceanprotocol.com/core-concepts/datanft-and-datatoken#revenue).", "help": "This address will receive the revenue from all sales. More info available in our [docs](https://docs.oceanprotocol.com/core-concepts/datanft-and-datatoken#revenue).",
"required": false "required": false
},
{
"name": "assetState",
"label": "Asset Status",
"help": "This asset will no longer be visible to other users and it won't be possible to purchase it. More info available in our [docs](https://docs.oceanprotocol.com/core-concepts/did-ddo#state).",
"type": "select",
"options": [
"Active",
"Revoked by publisher",
"Ordering is temporary disabled",
"Asset unlisted"
],
"sortOptions": false,
"required": false
} }
] ]
} }

66
package-lock.json generated
View File

@ -70,7 +70,7 @@
"@types/loadable__component": "^5.13.4", "@types/loadable__component": "^5.13.4",
"@types/node": "^18.8.5", "@types/node": "^18.8.5",
"@types/react": "^18.0.25", "@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9", "@types/react-dom": "^18.0.10",
"@types/react-modal": "^3.13.1", "@types/react-modal": "^3.13.1",
"@types/react-paginate": "^7.1.1", "@types/react-paginate": "^7.1.1",
"@types/remove-markdown": "^0.3.1", "@types/remove-markdown": "^0.3.1",
@ -85,12 +85,12 @@
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.11", "eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-testing-library": "^5.9.1", "eslint-plugin-testing-library": "^5.10.0",
"https-browserify": "^1.0.0", "https-browserify": "^1.0.0",
"husky": "^8.0.2", "husky": "^8.0.2",
"jest": "^29.3.1", "jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1", "jest-environment-jsdom": "^29.3.1",
"prettier": "^2.8.1", "prettier": "^2.8.3",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"process": "^0.11.10", "process": "^0.11.10",
"serve": "^14.1.2", "serve": "^14.1.2",
@ -17265,9 +17265,9 @@
} }
}, },
"node_modules/@types/react-dom": { "node_modules/@types/react-dom": {
"version": "18.0.9", "version": "18.0.10",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.9.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz",
"integrity": "sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==", "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/react": "*" "@types/react": "*"
@ -22559,9 +22559,9 @@
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
}, },
"node_modules/cookiejar": { "node_modules/cookiejar": {
"version": "2.1.3", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
"integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==" "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
}, },
"node_modules/copy-concurrently": { "node_modules/copy-concurrently": {
"version": "1.0.5", "version": "1.0.5",
@ -25105,12 +25105,12 @@
} }
}, },
"node_modules/eslint-plugin-testing-library": { "node_modules/eslint-plugin-testing-library": {
"version": "5.9.1", "version": "5.10.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.0.tgz",
"integrity": "sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ==", "integrity": "sha512-aTOsCAEI9trrX3TLOnsskfhe57DmsjP/yMKLPqg4ftdRvfR4qut2PGWUa8TwP7whZbwMzJjh98tgAPcE8vdHow==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@typescript-eslint/utils": "^5.13.0" "@typescript-eslint/utils": "^5.43.0"
}, },
"engines": { "engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0", "node": "^12.22.0 || ^14.17.0 || >=16.0.0",
@ -38418,9 +38418,9 @@
} }
}, },
"node_modules/prettier": { "node_modules/prettier": {
"version": "2.8.1", "version": "2.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
"dev": true, "dev": true,
"bin": { "bin": {
"prettier": "bin-prettier.js" "prettier": "bin-prettier.js"
@ -50195,6 +50195,7 @@
"cross-fetch": "^3.1.5", "cross-fetch": "^3.1.5",
"crypto-js": "^4.1.1", "crypto-js": "^4.1.1",
"decimal.js": "^10.4.1", "decimal.js": "^10.4.1",
"web3": "^1.8.1",
"web3-core": "^1.8.1", "web3-core": "^1.8.1",
"web3-eth-contract": "^1.8.1" "web3-eth-contract": "^1.8.1"
} }
@ -50255,6 +50256,7 @@
"integrity": "sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w==", "integrity": "sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w==",
"dev": true, "dev": true,
"requires": { "requires": {
"@oclif/config": "^1.18.2",
"@oclif/errors": "^1.3.5", "@oclif/errors": "^1.3.5",
"@oclif/help": "^1.0.1", "@oclif/help": "^1.0.1",
"@oclif/parser": "^3.8.6", "@oclif/parser": "^3.8.6",
@ -60045,9 +60047,9 @@
} }
}, },
"@types/react-dom": { "@types/react-dom": {
"version": "18.0.9", "version": "18.0.10",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.9.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz",
"integrity": "sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==", "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/react": "*" "@types/react": "*"
@ -61272,7 +61274,7 @@
"git-url-parse": "11.6.0", "git-url-parse": "11.6.0",
"glob": "8.0.1", "glob": "8.0.1",
"global-agent": "3.0.0", "global-agent": "3.0.0",
"graphql": "14.0.2 - 14.2.0 || ^14.3.1 || ^15.0.0", "graphql": "15.8.0",
"graphql-tag": "2.12.6", "graphql-tag": "2.12.6",
"listr": "0.14.3", "listr": "0.14.3",
"lodash.identity": "3.0.0", "lodash.identity": "3.0.0",
@ -61513,7 +61515,7 @@
"cosmiconfig": "^7.0.1", "cosmiconfig": "^7.0.1",
"dotenv": "^16.0.0", "dotenv": "^16.0.0",
"glob": "^8.0.0", "glob": "^8.0.0",
"graphql": "14.0.2 - 14.2.0 || ^14.3.1 || ^15.0.0", "graphql": "15.8.0",
"graphql-tag": "^2.10.1", "graphql-tag": "^2.10.1",
"lodash.debounce": "^4.0.8", "lodash.debounce": "^4.0.8",
"lodash.merge": "^4.6.1", "lodash.merge": "^4.6.1",
@ -64318,9 +64320,9 @@
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
}, },
"cookiejar": { "cookiejar": {
"version": "2.1.3", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
"integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==" "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw=="
}, },
"copy-concurrently": { "copy-concurrently": {
"version": "1.0.5", "version": "1.0.5",
@ -66384,12 +66386,12 @@
} }
}, },
"eslint-plugin-testing-library": { "eslint-plugin-testing-library": {
"version": "5.9.1", "version": "5.10.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.0.tgz",
"integrity": "sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ==", "integrity": "sha512-aTOsCAEI9trrX3TLOnsskfhe57DmsjP/yMKLPqg4ftdRvfR4qut2PGWUa8TwP7whZbwMzJjh98tgAPcE8vdHow==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/utils": "^5.13.0" "@typescript-eslint/utils": "^5.43.0"
} }
}, },
"eslint-scope": { "eslint-scope": {
@ -74392,6 +74394,7 @@
"integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==", "integrity": "sha512-uJx9y/1NIqoYTp6ZW1osJ7U5ZrXGAJbOQ/Qzl05BdGYvN1S7Qmbzid6xOirgK0EIT0pJKEEh1s8qbassYZe4cw==",
"peer": true, "peer": true,
"requires": { "requires": {
"@babel/core": "^7.14.0",
"@babel/plugin-proposal-async-generator-functions": "^7.0.0", "@babel/plugin-proposal-async-generator-functions": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-export-default-from": "^7.0.0", "@babel/plugin-proposal-export-default-from": "^7.0.0",
@ -74446,6 +74449,7 @@
"integrity": "sha512-Ogst/M6ujYrl/+9mpEWqE3zF7l2mTuftDTy3L8wZYwX1pWUQWQpfU1aJBeWiLxt1XlIq+uriRjKzKoRoIK57EA==", "integrity": "sha512-Ogst/M6ujYrl/+9mpEWqE3zF7l2mTuftDTy3L8wZYwX1pWUQWQpfU1aJBeWiLxt1XlIq+uriRjKzKoRoIK57EA==",
"peer": true, "peer": true,
"requires": { "requires": {
"@babel/core": "^7.14.0",
"babel-preset-fbjs": "^3.4.0", "babel-preset-fbjs": "^3.4.0",
"hermes-parser": "0.8.0", "hermes-parser": "0.8.0",
"metro-babel-transformer": "0.72.3", "metro-babel-transformer": "0.72.3",
@ -76714,9 +76718,9 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "2.8.1", "version": "2.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
"integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
"dev": true "dev": true
}, },
"prettier-linter-helpers": { "prettier-linter-helpers": {

View File

@ -83,7 +83,7 @@
"@types/loadable__component": "^5.13.4", "@types/loadable__component": "^5.13.4",
"@types/node": "^18.8.5", "@types/node": "^18.8.5",
"@types/react": "^18.0.25", "@types/react": "^18.0.25",
"@types/react-dom": "^18.0.9", "@types/react-dom": "^18.0.10",
"@types/react-modal": "^3.13.1", "@types/react-modal": "^3.13.1",
"@types/react-paginate": "^7.1.1", "@types/react-paginate": "^7.1.1",
"@types/remove-markdown": "^0.3.1", "@types/remove-markdown": "^0.3.1",
@ -98,12 +98,12 @@
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.31.11", "eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-testing-library": "^5.9.1", "eslint-plugin-testing-library": "^5.10.0",
"https-browserify": "^1.0.0", "https-browserify": "^1.0.0",
"husky": "^8.0.2", "husky": "^8.0.2",
"jest": "^29.3.1", "jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1", "jest-environment-jsdom": "^29.3.1",
"prettier": "^2.8.1", "prettier": "^2.8.3",
"pretty-quick": "^3.1.3", "pretty-quick": "^3.1.3",
"process": "^0.11.10", "process": "^0.11.10",
"serve": "^14.1.2", "serve": "^14.1.2",

View File

@ -16,6 +16,7 @@ import { getOceanConfig, getDevelopmentConfig } from '@utils/ocean'
import { getAccessDetails } from '@utils/accessDetailsAndPricing' import { getAccessDetails } from '@utils/accessDetailsAndPricing'
import { useIsMounted } from '@hooks/useIsMounted' import { useIsMounted } from '@hooks/useIsMounted'
import { useMarketMetadata } from './MarketMetadata' import { useMarketMetadata } from './MarketMetadata'
import { assetStateToString } from '@utils/assetState'
import { isValidDid } from '@utils/ddo' import { isValidDid } from '@utils/ddo'
export interface AssetProviderValue { export interface AssetProviderValue {
@ -29,6 +30,7 @@ export interface AssetProviderValue {
isOwner: boolean isOwner: boolean
oceanConfig: Config oceanConfig: Config
loading: boolean loading: boolean
assetState: string
fetchAsset: (token?: CancelToken) => Promise<void> fetchAsset: (token?: CancelToken) => Promise<void>
} }
@ -54,6 +56,7 @@ function AssetProvider({
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [isAssetNetwork, setIsAssetNetwork] = useState<boolean>() const [isAssetNetwork, setIsAssetNetwork] = useState<boolean>()
const [oceanConfig, setOceanConfig] = useState<Config>() const [oceanConfig, setOceanConfig] = useState<Config>()
const [assetState, setAssetState] = useState<string>()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
const isMounted = useIsMounted() const isMounted = useIsMounted()
@ -85,27 +88,16 @@ function AssetProvider({
return return
} }
if ([1, 2, 3].includes(asset.nft.state)) { if (asset.nft.state === (1 | 2 | 3)) {
// handle nft states as documented in https://docs.oceanprotocol.com/core-concepts/did-ddo/#state setTitle(
let state `This asset has been set as "${assetStateToString(
switch (asset.nft.state) { asset.nft.state
case 1: )}" by the publisher`
state = 'end-of-life' )
break
case 2:
state = 'deprecated'
break
case 3:
state = 'revoked'
break
}
setTitle(`This asset has been flagged as "${state}" by the publisher`)
setError(`\`${did}\`` + `\n\nPublisher Address: ${asset.nft.owner}`) setError(`\`${did}\`` + `\n\nPublisher Address: ${asset.nft.owner}`)
LoggerInstance.error(`[asset] Failed getting asset for ${did}`, asset) LoggerInstance.error(`[asset] Failed getting asset for ${did}`, asset)
return return
} }
if (asset) { if (asset) {
setError(undefined) setError(undefined)
setAsset((prevState) => ({ setAsset((prevState) => ({
@ -116,12 +108,13 @@ function AssetProvider({
setOwner(asset.nft?.owner) setOwner(asset.nft?.owner)
setIsInPurgatory(asset.purgatory?.state) setIsInPurgatory(asset.purgatory?.state)
setPurgatoryData(asset.purgatory) setPurgatoryData(asset.purgatory)
setAssetState(assetStateToString(asset.nft.state))
LoggerInstance.log('[asset] Got asset', asset) LoggerInstance.log('[asset] Got asset', asset)
} }
setLoading(false) setLoading(false)
}, },
[did] [did, accountId]
) )
// ----------------------------------- // -----------------------------------
@ -198,6 +191,14 @@ function AssetProvider({
setOceanConfig(oceanConfig) setOceanConfig(oceanConfig)
}, [asset?.chainId]) }, [asset?.chainId])
// -----------------------------------
// Set Asset State as a string
// -----------------------------------
useEffect(() => {
if (!asset?.nft) return
setAssetState(assetStateToString(asset.nft.state))
}, [asset])
return ( return (
<AssetContext.Provider <AssetContext.Provider
value={ value={
@ -213,7 +214,8 @@ function AssetProvider({
fetchAsset, fetchAsset,
isAssetNetwork, isAssetNetwork,
isOwner, isOwner,
oceanConfig oceanConfig,
assetState
} as AssetProviderValue } as AssetProviderValue
} }
> >

View File

@ -254,6 +254,7 @@ export async function getPublishedAssets(
const filters: FilterTerm[] = [] const filters: FilterTerm[] = []
filters.push(getFilterTerm('nft.state', [0, 4, 5]))
filters.push(getFilterTerm('nft.owner', accountId.toLowerCase())) filters.push(getFilterTerm('nft.owner', accountId.toLowerCase()))
accesType !== undefined && accesType !== undefined &&
filters.push(getFilterTerm('services.type', accesType)) filters.push(getFilterTerm('services.type', accesType))

39
src/@utils/assetState.ts Normal file
View File

@ -0,0 +1,39 @@
export function assetStateToString(state: number): string {
switch (state) {
case 0:
return 'Active'
case 1:
return 'End-of-life'
case 2:
return 'Deprecated (by another asset)'
case 3:
return 'Revoked by publisher'
case 4:
return 'Ordering is temporary disabled'
case 5:
return 'Asset unlisted'
default:
break
}
}
export function assetStateToNumber(state: string): number {
switch (state) {
case 'Active':
return 0
case 'End-of-life':
return 1
case 'Deprecated (by another asset)':
return 2
case 'Revoked by publisher':
return 3
case 'Ordering is temporary disabled':
return 4
case 'Asset unlisted':
return 5
default:
break
}
}

View File

@ -147,3 +147,14 @@ export async function downloadFile(
) )
await downloadFileBrowser(downloadUrl) await downloadFileBrowser(downloadUrl)
} }
export async function checkValidProvider(
providerUrl: string
): Promise<boolean> {
try {
const response = await ProviderInstance.isValidProvider(providerUrl)
return response
} catch (error) {
LoggerInstance.error(error.message)
}
}

View File

@ -1,3 +1,5 @@
import isUrl from 'is-url-superb'
export function sanitizeUrl(url: string) { export function sanitizeUrl(url: string) {
const u = decodeURI(url).trim().toLowerCase() const u = decodeURI(url).trim().toLowerCase()
const isAllowedUrlScheme = u.startsWith('http://') || u.startsWith('https://') const isAllowedUrlScheme = u.startsWith('http://') || u.startsWith('https://')
@ -6,7 +8,7 @@ export function sanitizeUrl(url: string) {
// check if the url is a google domain // check if the url is a google domain
export const isGoogleUrl = (url: string): boolean => { export const isGoogleUrl = (url: string): boolean => {
if (!url) return if (!url || !isUrl(url)) return
const googleUrl = new URL(url) const googleUrl = new URL(url)
return googleUrl.hostname.endsWith('google.com') return googleUrl.hostname.endsWith('google.com')
} }

View File

@ -2,7 +2,7 @@ import { fireEvent, render, screen } from '@testing-library/react'
import React from 'react' import React from 'react'
import FilesInput from './index' import FilesInput from './index'
import { useField } from 'formik' import { useField } from 'formik'
import { getFileInfo } from '@utils/provider' import { getFileInfo, checkValidProvider } from '@utils/provider'
jest.mock('formik') jest.mock('formik')
jest.mock('@utils/provider') jest.mock('@utils/provider')
@ -48,6 +48,7 @@ const mockForm = {
describe('@shared/FormInput/InputElement/FilesInput', () => { describe('@shared/FormInput/InputElement/FilesInput', () => {
it('renders without crashing', async () => { it('renders without crashing', async () => {
;(useField as jest.Mock).mockReturnValue([mockField, mockMeta, mockHelpers]) ;(useField as jest.Mock).mockReturnValue([mockField, mockMeta, mockHelpers])
;(checkValidProvider as jest.Mock).mockReturnValue(true)
;(getFileInfo as jest.Mock).mockReturnValue([ ;(getFileInfo as jest.Mock).mockReturnValue([
{ {
valid: true, valid: true,

View File

@ -3,7 +3,7 @@ import { useField } from 'formik'
import FileInfo from './Info' import FileInfo from './Info'
import UrlInput from '../URLInput' import UrlInput from '../URLInput'
import { InputProps } from '@shared/FormInput' import { InputProps } from '@shared/FormInput'
import { getFileInfo } from '@utils/provider' import { getFileInfo, checkValidProvider } from '@utils/provider'
import { LoggerInstance } from '@oceanprotocol/lib' import { LoggerInstance } from '@oceanprotocol/lib'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
import { isGoogleUrl } from '@utils/url/index' import { isGoogleUrl } from '@utils/url/index'
@ -33,6 +33,13 @@ export default function FilesInput(props: InputProps): ReactElement {
) )
} }
// Check if provider is a valid provider
const isValid = await checkValidProvider(providerUrl)
if (!isValid)
throw Error(
'✗ Provider cannot be reached, please check status.oceanprotocol.com and try again later.'
)
const checkedFile = await getFileInfo(url, providerUrl, storageType) const checkedFile = await getFileInfo(url, providerUrl, storageType)
// error if something's not right from response // error if something's not right from response

View File

@ -15,17 +15,18 @@ export default function Price({
size?: 'small' | 'mini' | 'large' size?: 'small' | 'mini' | 'large'
}): ReactElement { }): ReactElement {
const isSupported = const isSupported =
accessDetails?.type === 'fixed' || accessDetails?.type === 'free' (accessDetails?.type === 'fixed' || accessDetails?.type === 'free') &&
accessDetails?.baseToken?.symbol
const price = `${orderPriceAndFees?.price || accessDetails?.price}` const price = `${orderPriceAndFees?.price || accessDetails?.price}`
return isSupported ? ( return isSupported ? (
<PriceUnit <PriceUnit
price={Number(price)} price={Number(price)}
symbol={accessDetails.baseToken?.symbol} symbol={accessDetails?.baseToken?.symbol}
className={className} className={className}
size={size} size={size}
conversion={conversion} conversion={conversion}
type={accessDetails.type} type={accessDetails?.type}
/> />
) : null ) : null
} }

View File

@ -39,9 +39,9 @@ export default function AssetStats() {
</span> </span>
) : null} ) : null}
{!asset?.stats || asset?.stats?.orders < 0 ? ( {!asset?.stats || asset?.stats?.orders < 0 ? (
'N/A' <span className={styles.stat}>N/A</span>
) : asset?.stats?.orders === 0 ? ( ) : asset?.stats?.orders === 0 ? (
'No sales yet' <span className={styles.stat}>No sales yet</span>
) : ( ) : (
<span className={styles.stat}> <span className={styles.stat}>
<span className={styles.number}>{asset.stats.orders}</span> sale <span className={styles.number}>{asset.stats.orders}</span> sale

View File

@ -50,17 +50,20 @@ export default function Download({
useState<OrderPriceAndFees>() useState<OrderPriceAndFees>()
const [retry, setRetry] = useState<boolean>(false) const [retry, setRetry] = useState<boolean>(false)
const isUnsupportedPricing = asset?.accessDetails?.type === 'NOT_SUPPORTED' const isUnsupportedPricing =
asset?.accessDetails?.type === 'NOT_SUPPORTED' ||
(asset?.accessDetails?.type === 'fixed' &&
!asset?.accessDetails?.baseToken?.symbol)
useEffect(() => { useEffect(() => {
Number(asset?.nft.state) === 4 && setIsOrderDisabled(true) Number(asset?.nft.state) === 4 && setIsOrderDisabled(true)
}, [asset?.nft.state]) }, [asset?.nft.state])
useEffect(() => { useEffect(() => {
if (!asset?.accessDetails || isUnsupportedPricing) return if (!asset?.accessDetails || isUnsupportedPricing) return
asset.accessDetails.isOwned && setIsOwned(asset?.accessDetails?.isOwned) setIsOwned(asset?.accessDetails?.isOwned || false)
asset.accessDetails.validOrderTx && setValidOrderTx(asset?.accessDetails?.validOrderTx || '')
setValidOrderTx(asset?.accessDetails?.validOrderTx)
// get full price and fees // get full price and fees
async function init() { async function init() {

View File

@ -13,5 +13,6 @@ describe('src/components/Asset/AssetContent/MetaFull.tsx', () => {
it('renders metadata for an algorithm', () => { it('renders metadata for an algorithm', () => {
render(<MetaFull ddo={algorithmAquarius} />) render(<MetaFull ddo={algorithmAquarius} />)
expect(screen.getByText('Docker Image')).toBeInTheDocument() expect(screen.getByText('Docker Image')).toBeInTheDocument()
expect(screen.getByText('DID')).toBeInTheDocument()
}) })
}) })

View File

@ -3,14 +3,12 @@ import MetaItem from './MetaItem'
import styles from './MetaFull.module.css' import styles from './MetaFull.module.css'
import Publisher from '@shared/Publisher' import Publisher from '@shared/Publisher'
import { useAsset } from '@context/Asset' import { useAsset } from '@context/Asset'
// import { useWeb3 } from '@context/Web3'
import { getDummyWeb3 } from '@utils/web3' import { getDummyWeb3 } from '@utils/web3'
import { Asset, Datatoken, LoggerInstance } from '@oceanprotocol/lib' import { Asset, Datatoken, LoggerInstance } from '@oceanprotocol/lib'
export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement { export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement {
const [paymentCollector, setPaymentCollector] = useState<string>() const [paymentCollector, setPaymentCollector] = useState<string>()
const { isInPurgatory } = useAsset() const { isInPurgatory, assetState } = useAsset()
// const { web3 } = useWeb3()
useEffect(() => { useEffect(() => {
async function getInitialPaymentCollector() { async function getInitialPaymentCollector() {
@ -43,6 +41,9 @@ export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement {
title="Owner" title="Owner"
content={<Publisher account={ddo?.nft?.owner} />} content={<Publisher account={ddo?.nft?.owner} />}
/> />
{assetState !== 'Active' && (
<MetaItem title="Asset State" content={assetState} />
)}
{paymentCollector && paymentCollector !== ddo?.nft?.owner && ( {paymentCollector && paymentCollector !== ddo?.nft?.owner && (
<MetaItem <MetaItem
title="Revenue Sent To" title="Revenue Sent To"

View File

@ -6,7 +6,8 @@ import {
FixedRateExchange, FixedRateExchange,
Asset, Asset,
Service, Service,
Datatoken Datatoken,
Nft
} from '@oceanprotocol/lib' } from '@oceanprotocol/lib'
import { validationSchema } from './_validation' import { validationSchema } from './_validation'
import { getInitialValues } from './_constants' import { getInitialValues } from './_constants'
@ -26,6 +27,7 @@ import { useAsset } from '@context/Asset'
import { setNftMetadata } from '@utils/nft' import { setNftMetadata } from '@utils/nft'
import { sanitizeUrl } from '@utils/url' import { sanitizeUrl } from '@utils/url'
import { getEncryptedFiles } from '@utils/provider' import { getEncryptedFiles } from '@utils/provider'
import { assetStateToNumber } from '@utils/assetState'
export default function Edit({ export default function Edit({
asset asset
@ -33,7 +35,7 @@ export default function Edit({
asset: AssetExtended asset: AssetExtended
}): ReactElement { }): ReactElement {
const { debug } = useUserPreferences() const { debug } = useUserPreferences()
const { fetchAsset, isAssetNetwork } = useAsset() const { fetchAsset, isAssetNetwork, assetState } = useAsset()
const { accountId, web3 } = useWeb3() const { accountId, web3 } = useWeb3()
const newAbortController = useAbortController() const newAbortController = useAbortController()
const [success, setSuccess] = useState<string>() const [success, setSuccess] = useState<string>()
@ -157,6 +159,16 @@ export default function Edit({
newAbortController() newAbortController()
) )
if (values.assetState !== assetState) {
const nft = new Nft(web3)
await nft.setMetadataState(
asset?.nftAddress,
accountId,
assetStateToNumber(values.assetState)
)
}
LoggerInstance.log('[edit] setMetadata result', setMetadataTx) LoggerInstance.log('[edit] setMetadata result', setMetadataTx)
if (!setMetadataTx) { if (!setMetadataTx) {
@ -177,7 +189,8 @@ export default function Edit({
asset?.metadata, asset?.metadata,
asset?.services[0]?.timeout, asset?.services[0]?.timeout,
asset?.accessDetails?.price || '0', asset?.accessDetails?.price || '0',
paymentCollector paymentCollector,
assetState
) as unknown as FormEditMetadataValues ) as unknown as FormEditMetadataValues
return ( return (

View File

@ -199,7 +199,7 @@ export default function FormEditMetadata({
</span> </span>
<Field {...getFieldContent('tags', data)} component={Input} name="tags" /> <Field {...getFieldContent('tags', data)} component={Input} name="tags" />
<span <span
className={ className={
Object.keys(diff).includes( Object.keys(diff).includes(
@ -216,6 +216,12 @@ export default function FormEditMetadata({
/> />
</span> </span>
<Field
{...getFieldContent('assetState', data)}
component={Input}
name="assetState"
/>
<FormActions /> <FormActions />
</Form> </Form>
) )

View File

@ -6,7 +6,8 @@ export function getInitialValues(
metadata: Metadata, metadata: Metadata,
timeout: number, timeout: number,
price: string, price: string,
paymentCollector: string paymentCollector: string,
assetState: string
): Partial<MetadataEditForm> { ): Partial<MetadataEditForm> {
return { return {
name: metadata?.name, name: metadata?.name,
@ -17,7 +18,8 @@ export function getInitialValues(
timeout: secondsToString(timeout), timeout: secondsToString(timeout),
author: metadata?.author, author: metadata?.author,
tags: metadata?.tags, tags: metadata?.tags,
paymentCollector paymentCollector,
assetState
} }
} }

View File

@ -9,6 +9,7 @@ export interface MetadataEditForm {
links?: FileInfo[] links?: FileInfo[]
author?: string author?: string
tags?: string[] tags?: string[]
assetState?: string
} }
export interface ComputeEditForm { export interface ComputeEditForm {

View File

@ -43,7 +43,8 @@ export const validationSchema = Yup.object().shape({
(value) => { (value) => {
return web3.utils.isAddress(value) return web3.utils.isAddress(value)
} }
) ),
retireAsset: Yup.string()
}) })
export const computeSettingsValidationSchema = Yup.object().shape({ export const computeSettingsValidationSchema = Yup.object().shape({

View File

@ -22,23 +22,6 @@ export default function PricingFields(): ReactElement {
token.name.toLowerCase().includes('ocean') token.name.toLowerCase().includes('ocean')
) || approvedBaseTokens?.[0] ) || approvedBaseTokens?.[0]
const isBaseTokenSet = !!approvedBaseTokens?.find(
(token) => token?.address === values?.pricing?.baseToken?.address
)
useEffect(() => {
if (!approvedBaseTokens?.length) return
if (isBaseTokenSet) return
setFieldValue('pricing.baseToken', defaultBaseToken)
}, [
approvedBaseTokens,
chainId,
defaultBaseToken,
isBaseTokenSet,
setFieldValue,
values.pricing.baseToken
])
// Switch type value upon tab change // Switch type value upon tab change
function handleTabChange(tabName: string) { function handleTabChange(tabName: string) {
const type = tabName.toLowerCase() const type = tabName.toLowerCase()

View File

@ -10,7 +10,7 @@ export function Steps({
}: { }: {
feedback: PublishFeedback feedback: PublishFeedback
}): ReactElement { }): ReactElement {
const { chainId, accountId } = useWeb3() const { chainId, accountId, approvedBaseTokens } = useWeb3()
const { values, setFieldValue, touched, setTouched } = const { values, setFieldValue, touched, setTouched } =
useFormikContext<FormPublishData>() useFormikContext<FormPublishData>()
@ -24,6 +24,21 @@ export function Steps({
setFieldValue('user.accountId', accountId) setFieldValue('user.accountId', accountId)
}, [chainId, accountId, setFieldValue]) }, [chainId, accountId, setFieldValue])
useEffect(() => {
if (!approvedBaseTokens?.length) return
const defaultBaseToken =
approvedBaseTokens?.find((token) =>
token.name.toLowerCase().includes('ocean')
) || approvedBaseTokens?.[0]
const isBaseTokenSet = !!approvedBaseTokens?.find(
(token) => token?.address === values?.pricing?.baseToken?.address
)
if (isBaseTokenSet) return
setFieldValue('pricing.baseToken', defaultBaseToken)
}, [approvedBaseTokens])
// auto-sync publish feedback into form data values // auto-sync publish feedback into form data values
useEffect(() => { useEffect(() => {
setFieldValue('feedback', feedback) setFieldValue('feedback', feedback)