mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
new publish preview (#947)
* refactor preview * make preview render * more preview elements, proper debug output * make more elements work * cleanup and fixes * make asset actions preview work, kinda * more fixes * reorg * make preview price display work * fix timeout * layout tweaks * fixes * another fix * make file info preview work * empty render fix
This commit is contained in:
parent
c387b27f23
commit
c484a5b40c
@ -129,7 +129,7 @@ function usePricing(): UsePricing {
|
|||||||
Decimal.set({ precision: 18 })
|
Decimal.set({ precision: 18 })
|
||||||
|
|
||||||
switch (price?.type) {
|
switch (price?.type) {
|
||||||
case 'pool': {
|
case 'dynamic': {
|
||||||
const oceanAmmount = new Decimal(price.value).times(1.05).toString()
|
const oceanAmmount = new Decimal(price.value).times(1.05).toString()
|
||||||
const maxPrice = new Decimal(price.value).times(2).toString()
|
const maxPrice = new Decimal(price.value).times(2).toString()
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ function usePricing(): UsePricing {
|
|||||||
Logger.log('DT buy response', tx)
|
Logger.log('DT buy response', tx)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'exchange': {
|
case 'fixed': {
|
||||||
if (!config.oceanTokenAddress) {
|
if (!config.oceanTokenAddress) {
|
||||||
Logger.error(`'oceanTokenAddress' not set in config`)
|
Logger.error(`'oceanTokenAddress' not set in config`)
|
||||||
return
|
return
|
||||||
|
2
src/@types/DDO/Services.d.ts
vendored
2
src/@types/DDO/Services.d.ts
vendored
@ -22,7 +22,7 @@ interface Service {
|
|||||||
files: string
|
files: string
|
||||||
datatokenAddress: string
|
datatokenAddress: string
|
||||||
serviceEndpoint: string
|
serviceEndpoint: string
|
||||||
timeout: string
|
timeout: number
|
||||||
name?: string
|
name?: string
|
||||||
description?: string
|
description?: string
|
||||||
compute?: ServiceComputeOptions
|
compute?: ServiceComputeOptions
|
||||||
|
4
src/@types/Price.d.ts
vendored
4
src/@types/Price.d.ts
vendored
@ -1,5 +1,5 @@
|
|||||||
interface BestPrice {
|
interface BestPrice {
|
||||||
type: 'pool' | 'exchange' | 'free' | ''
|
type: 'dynamic' | 'fixed' | 'free' | ''
|
||||||
address: string
|
address: string
|
||||||
value: number
|
value: number
|
||||||
isConsumable?: 'true' | 'false' | ''
|
isConsumable?: 'true' | 'false' | ''
|
||||||
@ -15,7 +15,7 @@ interface PriceOptions {
|
|||||||
price: number
|
price: number
|
||||||
amountDataToken: number
|
amountDataToken: number
|
||||||
amountOcean: number
|
amountOcean: number
|
||||||
type: 'fixed' | 'dynamic' | 'free' | string
|
type: 'dynamic' | 'fixed' | 'free' | ''
|
||||||
weightOnDataToken: string
|
weightOnDataToken: string
|
||||||
weightOnOcean: string
|
weightOnOcean: string
|
||||||
// easier to keep this as number for Yup input validation
|
// easier to keep this as number for Yup input validation
|
||||||
|
@ -2,6 +2,8 @@ import axios, { CancelToken, AxiosResponse } from 'axios'
|
|||||||
import { DID, Logger } from '@oceanprotocol/lib'
|
import { DID, Logger } from '@oceanprotocol/lib'
|
||||||
|
|
||||||
export interface FileMetadata {
|
export interface FileMetadata {
|
||||||
|
index: number
|
||||||
|
valid: boolean
|
||||||
contentType: string
|
contentType: string
|
||||||
contentLength: string
|
contentLength: string
|
||||||
}
|
}
|
||||||
@ -35,20 +37,13 @@ export async function getFileInfo(
|
|||||||
): Promise<FileMetadata[]> {
|
): Promise<FileMetadata[]> {
|
||||||
let postBody
|
let postBody
|
||||||
try {
|
try {
|
||||||
if (url instanceof DID)
|
if (url instanceof DID) postBody = { did: url.getDid() }
|
||||||
postBody = {
|
else postBody = { url }
|
||||||
did: url.getDid()
|
|
||||||
}
|
|
||||||
else
|
|
||||||
postBody = {
|
|
||||||
url
|
|
||||||
}
|
|
||||||
const response: AxiosResponse<FileMetadata[]> = await axios.post(
|
const response: AxiosResponse<FileMetadata[]> = await axios.post(
|
||||||
`${providerUrl}/api/v1/services/fileinfo`,
|
`${providerUrl}/api/v1/services/fileinfo`,
|
||||||
postBody,
|
postBody,
|
||||||
{
|
{ cancelToken }
|
||||||
cancelToken
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!response || response.status !== 200 || !response.data) return
|
if (!response || response.status !== 200 || !response.data) return
|
||||||
|
@ -346,7 +346,7 @@ function transformPriceToBestPrice(
|
|||||||
) {
|
) {
|
||||||
if (poolPrice?.length > 0) {
|
if (poolPrice?.length > 0) {
|
||||||
const price: BestPrice = {
|
const price: BestPrice = {
|
||||||
type: 'pool',
|
type: 'dynamic',
|
||||||
address: poolPrice[0]?.id,
|
address: poolPrice[0]?.id,
|
||||||
value:
|
value:
|
||||||
poolPrice[0]?.consumePrice === '-1'
|
poolPrice[0]?.consumePrice === '-1'
|
||||||
@ -363,7 +363,7 @@ function transformPriceToBestPrice(
|
|||||||
// TODO Hacky hack, temporary™: set isConsumable to true for fre assets.
|
// TODO Hacky hack, temporary™: set isConsumable to true for fre assets.
|
||||||
// isConsumable: 'true'
|
// isConsumable: 'true'
|
||||||
const price: BestPrice = {
|
const price: BestPrice = {
|
||||||
type: 'exchange',
|
type: 'fixed',
|
||||||
value: frePrice[0]?.rate,
|
value: frePrice[0]?.rate,
|
||||||
address: frePrice[0]?.id,
|
address: frePrice[0]?.id,
|
||||||
exchangeId: frePrice[0]?.id,
|
exchangeId: frePrice[0]?.id,
|
||||||
|
@ -3,7 +3,7 @@ import { Logger } from '@oceanprotocol/lib'
|
|||||||
import { getOceanConfig } from './ocean'
|
import { getOceanConfig } from './ocean'
|
||||||
|
|
||||||
export function accountTruncate(account: string): string {
|
export function accountTruncate(account: string): string {
|
||||||
if (!account) return
|
if (!account || account === '') return
|
||||||
const middle = account.substring(6, 38)
|
const middle = account.substring(6, 38)
|
||||||
const truncated = account.replace(middle, '…')
|
const truncated = account.replace(middle, '…')
|
||||||
return truncated
|
return truncated
|
||||||
|
@ -10,7 +10,7 @@ export default function DebugOutput({
|
|||||||
return (
|
return (
|
||||||
<div style={{ marginTop: 'var(--spacer)' }}>
|
<div style={{ marginTop: 'var(--spacer)' }}>
|
||||||
<h5>{title}</h5>
|
<h5>{title}</h5>
|
||||||
<pre>
|
<pre style={{ wordWrap: 'break-word' }}>
|
||||||
<code>{JSON.stringify(output, null, 2)}</code>
|
<code>{JSON.stringify(output, null, 2)}</code>
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,7 @@ export default function FileInfo({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.info}>
|
<div className={styles.info}>
|
||||||
{/* <h3 className={styles.url}>{file}</h3> */}
|
<h3 className={styles.url}>{(file as any).url}</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>URL confirmed</li>
|
<li>URL confirmed</li>
|
||||||
{file.contentLength && <li>{prettySize(+file.contentLength)}</li>}
|
{file.contentLength && <li>{prettySize(+file.contentLength)}</li>}
|
||||||
|
@ -27,7 +27,7 @@ export default function FilesInput(props: InputProps): ReactElement {
|
|||||||
config?.providerUri,
|
config?.providerUri,
|
||||||
newCancelToken()
|
newCancelToken()
|
||||||
)
|
)
|
||||||
checkedFile && helpers.setValue([checkedFile])
|
checkedFile && helpers.setValue([{ url: fileUrl, ...checkedFile[0] }])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error('Could not fetch file info. Please check URL and try again')
|
toast.error('Could not fetch file info. Please check URL and try again')
|
||||||
console.error(error.message)
|
console.error(error.message)
|
||||||
|
@ -21,13 +21,13 @@ export default function Publisher({
|
|||||||
minimal?: boolean
|
minimal?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { accountId } = useWeb3()
|
// const { accountId } = useWeb3()
|
||||||
const isMounted = useIsMounted()
|
const isMounted = useIsMounted()
|
||||||
const [profile, setProfile] = useState<Profile>()
|
const [profile, setProfile] = useState<Profile>()
|
||||||
const [name, setName] = useState(accountTruncate(account))
|
const [name, setName] = useState(accountTruncate(account))
|
||||||
const [accountEns, setAccountEns] = useState<string>()
|
const [accountEns, setAccountEns] = useState<string>()
|
||||||
|
|
||||||
const showAdd = account === accountId && !profile
|
// const showAdd = account === accountId && !profile
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!account) return
|
if (!account) return
|
||||||
@ -70,7 +70,7 @@ export default function Publisher({
|
|||||||
<Link href={`/profile/${accountEns || account}`}>
|
<Link href={`/profile/${accountEns || account}`}>
|
||||||
<a title="Show profile page.">{name}</a>
|
<a title="Show profile page.">{name}</a>
|
||||||
</Link>
|
</Link>
|
||||||
{showAdd && <Add />}
|
{/* {showAdd && <Add />} */}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -34,6 +34,10 @@
|
|||||||
border-color: var(--font-color-heading);
|
border-color: var(--font-color-heading);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab[aria-disabled='true'] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.tabContent {
|
.tabContent {
|
||||||
padding: calc(var(--spacer) / 2);
|
padding: calc(var(--spacer) / 2);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,10 @@ import React, { ReactElement, ReactNode } from 'react'
|
|||||||
import { Tab, Tabs as ReactTabs, TabList, TabPanel } from 'react-tabs'
|
import { Tab, Tabs as ReactTabs, TabList, TabPanel } from 'react-tabs'
|
||||||
import styles from './Tabs.module.css'
|
import styles from './Tabs.module.css'
|
||||||
|
|
||||||
interface TabsItem {
|
export interface TabsItem {
|
||||||
title: string
|
title: string
|
||||||
content: ReactNode
|
content: ReactNode
|
||||||
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Tabs({
|
export default function Tabs({
|
||||||
@ -29,6 +30,7 @@ export default function Tabs({
|
|||||||
className={styles.tab}
|
className={styles.tab}
|
||||||
key={item.title}
|
key={item.title}
|
||||||
onClick={handleTabChange ? () => handleTabChange(item.title) : null}
|
onClick={handleTabChange ? () => handleTabChange(item.title) : null}
|
||||||
|
disabled={item.disabled}
|
||||||
>
|
>
|
||||||
{item.title}
|
{item.title}
|
||||||
</Tab>
|
</Tab>
|
||||||
|
@ -3,38 +3,39 @@ import styles from './AlgorithmDatasetsListForCompute.module.css'
|
|||||||
import { getAlgorithmDatasetsForCompute } from '@utils/aquarius'
|
import { getAlgorithmDatasetsForCompute } from '@utils/aquarius'
|
||||||
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
import { AssetSelectionAsset } from '@shared/FormFields/AssetSelection'
|
||||||
import AssetComputeList from '@shared/AssetList/AssetComputeList'
|
import AssetComputeList from '@shared/AssetList/AssetComputeList'
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
|
|
||||||
export default function AlgorithmDatasetsListForCompute({
|
export default function AlgorithmDatasetsListForCompute({
|
||||||
algorithmDid,
|
ddo,
|
||||||
dataset
|
algorithmDid
|
||||||
}: {
|
}: {
|
||||||
|
ddo: Asset
|
||||||
algorithmDid: string
|
algorithmDid: string
|
||||||
dataset: Asset
|
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { ddo } = useAsset()
|
|
||||||
const [datasetsForCompute, setDatasetsForCompute] =
|
const [datasetsForCompute, setDatasetsForCompute] =
|
||||||
useState<AssetSelectionAsset[]>()
|
useState<AssetSelectionAsset[]>()
|
||||||
const newCancelToken = useCancelToken()
|
const newCancelToken = useCancelToken()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!ddo) return
|
||||||
|
|
||||||
async function getDatasetsAllowedForCompute() {
|
async function getDatasetsAllowedForCompute() {
|
||||||
const isCompute = Boolean(getServiceByName(dataset, 'compute'))
|
const isCompute = Boolean(getServiceByName(ddo, 'compute'))
|
||||||
const datasetComputeService = getServiceByName(
|
const datasetComputeService = getServiceByName(
|
||||||
dataset,
|
ddo,
|
||||||
isCompute ? 'compute' : 'access'
|
isCompute ? 'compute' : 'access'
|
||||||
)
|
)
|
||||||
const datasets = await getAlgorithmDatasetsForCompute(
|
const datasets = await getAlgorithmDatasetsForCompute(
|
||||||
algorithmDid,
|
algorithmDid,
|
||||||
datasetComputeService?.serviceEndpoint,
|
datasetComputeService?.serviceEndpoint,
|
||||||
dataset?.chainId,
|
ddo?.chainId,
|
||||||
newCancelToken()
|
newCancelToken()
|
||||||
)
|
)
|
||||||
setDatasetsForCompute(datasets)
|
setDatasetsForCompute(datasets)
|
||||||
}
|
}
|
||||||
ddo.metadata.type === 'algorithm' && getDatasetsAllowedForCompute()
|
ddo.metadata.type === 'algorithm' && getDatasetsAllowedForCompute()
|
||||||
}, [ddo.metadata.type])
|
}, [ddo?.metadata?.type])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.datasetsContainer}>
|
<div className={styles.datasetsContainer}>
|
||||||
|
@ -160,7 +160,7 @@ export default function FormStartCompute({
|
|||||||
}
|
}
|
||||||
hasPreviousOrder={hasPreviousOrder}
|
hasPreviousOrder={hasPreviousOrder}
|
||||||
hasDatatoken={hasDatatoken}
|
hasDatatoken={hasDatatoken}
|
||||||
dtSymbol={ddo.dataTokenInfo.symbol}
|
dtSymbol={ddo?.dataTokenInfo?.symbol}
|
||||||
dtBalance={dtBalance}
|
dtBalance={dtBalance}
|
||||||
datasetLowPoolLiquidity={datasetLowPoolLiquidity}
|
datasetLowPoolLiquidity={datasetLowPoolLiquidity}
|
||||||
assetTimeout={assetTimeout}
|
assetTimeout={assetTimeout}
|
||||||
|
@ -37,12 +37,16 @@ import { SortTermOptions } from '../../../../@types/aquarius/SearchQuery'
|
|||||||
import { FileMetadata } from '@utils/provider'
|
import { FileMetadata } from '@utils/provider'
|
||||||
|
|
||||||
export default function Compute({
|
export default function Compute({
|
||||||
|
ddo,
|
||||||
|
price,
|
||||||
dtBalance,
|
dtBalance,
|
||||||
file,
|
file,
|
||||||
fileIsLoading,
|
fileIsLoading,
|
||||||
isConsumable,
|
isConsumable,
|
||||||
consumableFeedback
|
consumableFeedback
|
||||||
}: {
|
}: {
|
||||||
|
ddo: Asset
|
||||||
|
price: BestPrice
|
||||||
dtBalance: string
|
dtBalance: string
|
||||||
file: FileMetadata
|
file: FileMetadata
|
||||||
fileIsLoading?: boolean
|
fileIsLoading?: boolean
|
||||||
@ -51,8 +55,7 @@ export default function Compute({
|
|||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { appConfig } = useSiteMetadata()
|
const { appConfig } = useSiteMetadata()
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { ocean, account } = useOcean()
|
const { ocean } = useOcean()
|
||||||
const { price, ddo } = useAsset()
|
|
||||||
const { buyDT, pricingError, pricingStepText } = usePricing()
|
const { buyDT, pricingError, pricingStepText } = usePricing()
|
||||||
const [isJobStarting, setIsJobStarting] = useState(false)
|
const [isJobStarting, setIsJobStarting] = useState(false)
|
||||||
const [error, setError] = useState<string>()
|
const [error, setError] = useState<string>()
|
||||||
@ -399,10 +402,7 @@ export default function Compute({
|
|||||||
text="This algorithm has been set to private by the publisher and can't be downloaded. You can run it against any allowed data sets though!"
|
text="This algorithm has been set to private by the publisher and can't be downloaded. You can run it against any allowed data sets though!"
|
||||||
state="info"
|
state="info"
|
||||||
/>
|
/>
|
||||||
<AlgorithmDatasetsListForCompute
|
<AlgorithmDatasetsListForCompute algorithmDid={ddo.id} ddo={ddo} />
|
||||||
algorithmDid={ddo.id}
|
|
||||||
dataset={ddo}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Formik
|
<Formik
|
||||||
@ -423,7 +423,7 @@ export default function Compute({
|
|||||||
hasDatatoken={hasDatatoken}
|
hasDatatoken={hasDatatoken}
|
||||||
dtBalance={dtBalance}
|
dtBalance={dtBalance}
|
||||||
datasetLowPoolLiquidity={!isConsumablePrice}
|
datasetLowPoolLiquidity={!isConsumablePrice}
|
||||||
assetType={ddo.metadata.type}
|
assetType={ddo?.metadata.type}
|
||||||
assetTimeout={datasetTimeout}
|
assetTimeout={datasetTimeout}
|
||||||
hasPreviousOrderSelectedComputeAsset={hasPreviousAlgorithmOrder}
|
hasPreviousOrderSelectedComputeAsset={hasPreviousAlgorithmOrder}
|
||||||
hasDatatokenSelectedComputeAsset={hasAlgoAssetDatatoken}
|
hasDatatokenSelectedComputeAsset={hasAlgoAssetDatatoken}
|
||||||
@ -448,7 +448,7 @@ export default function Compute({
|
|||||||
<SuccessConfetti success="Your job started successfully! Watch the progress below or on your profile." />
|
<SuccessConfetti success="Your job started successfully! Watch the progress below or on your profile." />
|
||||||
)}
|
)}
|
||||||
</footer>
|
</footer>
|
||||||
{accountId && (
|
{accountId && price?.datatoken && (
|
||||||
<AssetActionHistoryTable title="Your Compute Jobs">
|
<AssetActionHistoryTable title="Your Compute Jobs">
|
||||||
<ComputeJobs minimal />
|
<ComputeJobs minimal />
|
||||||
</AssetActionHistoryTable>
|
</AssetActionHistoryTable>
|
||||||
|
@ -8,7 +8,6 @@ import { gql } from 'urql'
|
|||||||
import { fetchData, getQueryContext } from '@utils/subgraph'
|
import { fetchData, getQueryContext } from '@utils/subgraph'
|
||||||
import { OrdersData } from '../../../@types/apollo/OrdersData'
|
import { OrdersData } from '../../../@types/apollo/OrdersData'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { useOcean } from '@context/Ocean'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
import { useWeb3 } from '@context/Web3'
|
||||||
import { usePricing } from '@hooks/usePricing'
|
import { usePricing } from '@hooks/usePricing'
|
||||||
import { useConsume } from '@hooks/useConsume'
|
import { useConsume } from '@hooks/useConsume'
|
||||||
@ -35,6 +34,7 @@ const previousOrderQuery = gql`
|
|||||||
|
|
||||||
export default function Consume({
|
export default function Consume({
|
||||||
ddo,
|
ddo,
|
||||||
|
price,
|
||||||
file,
|
file,
|
||||||
isBalanceSufficient,
|
isBalanceSufficient,
|
||||||
dtBalance,
|
dtBalance,
|
||||||
@ -43,6 +43,7 @@ export default function Consume({
|
|||||||
consumableFeedback
|
consumableFeedback
|
||||||
}: {
|
}: {
|
||||||
ddo: Asset
|
ddo: Asset
|
||||||
|
price: BestPrice
|
||||||
file: FileMetadata
|
file: FileMetadata
|
||||||
isBalanceSufficient: boolean
|
isBalanceSufficient: boolean
|
||||||
dtBalance: string
|
dtBalance: string
|
||||||
@ -51,11 +52,10 @@ export default function Consume({
|
|||||||
consumableFeedback?: string
|
consumableFeedback?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const { ocean } = useOcean()
|
|
||||||
const { appConfig } = useSiteMetadata()
|
const { appConfig } = useSiteMetadata()
|
||||||
const [hasPreviousOrder, setHasPreviousOrder] = useState(false)
|
const [hasPreviousOrder, setHasPreviousOrder] = useState(false)
|
||||||
const [previousOrderId, setPreviousOrderId] = useState<string>()
|
const [previousOrderId, setPreviousOrderId] = useState<string>()
|
||||||
const { isInPurgatory, price, isAssetNetwork } = useAsset()
|
const { isInPurgatory, isAssetNetwork } = useAsset()
|
||||||
const { buyDT, pricingStepText, pricingError, pricingIsLoading } =
|
const { buyDT, pricingStepText, pricingError, pricingIsLoading } =
|
||||||
usePricing()
|
usePricing()
|
||||||
const { consumeStepText, consume, consumeError, isLoading } = useConsume()
|
const { consumeStepText, consume, consumeError, isLoading } = useConsume()
|
||||||
@ -105,6 +105,8 @@ export default function Consume({
|
|||||||
}, [data, assetTimeout, accountId, isAssetNetwork])
|
}, [data, assetTimeout, accountId, isAssetNetwork])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!ddo) return
|
||||||
|
|
||||||
const { timeout } = ddo.services[0]
|
const { timeout } = ddo.services[0]
|
||||||
setAssetTimeout(`${timeout}`)
|
setAssetTimeout(`${timeout}`)
|
||||||
}, [ddo])
|
}, [ddo])
|
||||||
@ -125,8 +127,7 @@ export default function Consume({
|
|||||||
if (!accountId) return
|
if (!accountId) return
|
||||||
setIsDisabled(
|
setIsDisabled(
|
||||||
!isConsumable ||
|
!isConsumable ||
|
||||||
((!ocean ||
|
((!isBalanceSufficient ||
|
||||||
!isBalanceSufficient ||
|
|
||||||
!isAssetNetwork ||
|
!isAssetNetwork ||
|
||||||
typeof consumeStepText !== 'undefined' ||
|
typeof consumeStepText !== 'undefined' ||
|
||||||
pricingIsLoading ||
|
pricingIsLoading ||
|
||||||
@ -135,7 +136,6 @@ export default function Consume({
|
|||||||
!hasDatatoken)
|
!hasDatatoken)
|
||||||
)
|
)
|
||||||
}, [
|
}, [
|
||||||
ocean,
|
|
||||||
hasPreviousOrder,
|
hasPreviousOrder,
|
||||||
isBalanceSufficient,
|
isBalanceSufficient,
|
||||||
isAssetNetwork,
|
isAssetNetwork,
|
||||||
@ -182,7 +182,7 @@ export default function Consume({
|
|||||||
datasetLowPoolLiquidity={!isConsumablePrice}
|
datasetLowPoolLiquidity={!isConsumablePrice}
|
||||||
onClick={handleConsume}
|
onClick={handleConsume}
|
||||||
assetTimeout={secondsToString(parseInt(assetTimeout))}
|
assetTimeout={secondsToString(parseInt(assetTimeout))}
|
||||||
assetType={ddo?.metadata.type}
|
assetType={ddo?.metadata?.type}
|
||||||
stepText={consumeStepText || pricingStepText}
|
stepText={consumeStepText || pricingStepText}
|
||||||
isLoading={pricingIsLoading || isLoading}
|
isLoading={pricingIsLoading || isLoading}
|
||||||
priceType={price?.type}
|
priceType={price?.type}
|
||||||
@ -203,8 +203,8 @@ export default function Consume({
|
|||||||
{!isInPurgatory && <PurchaseButton />}
|
{!isInPurgatory && <PurchaseButton />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ddo.metadata.type === 'algorithm' && (
|
{ddo?.metadata?.type === 'algorithm' && (
|
||||||
<AlgorithmDatasetsListForCompute algorithmDid={ddo.id} dataset={ddo} />
|
<AlgorithmDatasetsListForCompute algorithmDid={ddo.id} ddo={ddo} />
|
||||||
)}
|
)}
|
||||||
</aside>
|
</aside>
|
||||||
)
|
)
|
||||||
|
@ -2,7 +2,7 @@ import React, { ReactElement, useState, useEffect } from 'react'
|
|||||||
import Compute from './Compute'
|
import Compute from './Compute'
|
||||||
import Consume from './Consume'
|
import Consume from './Consume'
|
||||||
import { Logger } from '@oceanprotocol/lib'
|
import { Logger } from '@oceanprotocol/lib'
|
||||||
import Tabs from '@shared/atoms/Tabs'
|
import Tabs, { TabsItem } from '@shared/atoms/Tabs'
|
||||||
import { compareAsBN } from '@utils/numbers'
|
import { compareAsBN } from '@utils/numbers'
|
||||||
import Pool from './Pool'
|
import Pool from './Pool'
|
||||||
import Trade from './Trade'
|
import Trade from './Trade'
|
||||||
@ -15,11 +15,20 @@ import { getOceanConfig } from '@utils/ocean'
|
|||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { useIsMounted } from '@hooks/useIsMounted'
|
import { useIsMounted } from '@hooks/useIsMounted'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
|
import { useFormikContext } from 'formik'
|
||||||
|
import { FormPublishData } from 'src/components/Publish/_types'
|
||||||
|
|
||||||
export default function AssetActions(): ReactElement {
|
export default function AssetActions({
|
||||||
|
ddo,
|
||||||
|
price
|
||||||
|
}: {
|
||||||
|
ddo: Asset
|
||||||
|
price: BestPrice
|
||||||
|
}): ReactElement {
|
||||||
const { accountId, balance } = useWeb3()
|
const { accountId, balance } = useWeb3()
|
||||||
const { ocean, account } = useOcean()
|
const { ocean, account } = useOcean()
|
||||||
const { price, ddo, isAssetNetwork } = useAsset()
|
const { isAssetNetwork } = useAsset()
|
||||||
|
const { values } = useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
const [isBalanceSufficient, setIsBalanceSufficient] = useState<boolean>()
|
||||||
const [dtBalance, setDtBalance] = useState<string>()
|
const [dtBalance, setDtBalance] = useState<string>()
|
||||||
@ -51,25 +60,30 @@ export default function AssetActions(): ReactElement {
|
|||||||
// }, [accountId, isAssetNetwork, ddo, ocean])
|
// }, [accountId, isAssetNetwork, ddo, ocean])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const oceanConfig = getOceanConfig(ddo.chainId)
|
const oceanConfig = getOceanConfig(ddo?.chainId)
|
||||||
if (!oceanConfig) return
|
if (!oceanConfig) return
|
||||||
|
|
||||||
async function initFileInfo() {
|
async function initFileInfo() {
|
||||||
setFileIsLoading(true)
|
setFileIsLoading(true)
|
||||||
|
|
||||||
|
const asset = values?.services?.[0].files?.[0].url || ddo.id
|
||||||
|
const providerUrl =
|
||||||
|
values?.services[0].providerUrl || oceanConfig.providerUri
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fileInfoResponse = await getFileInfo(
|
const fileInfoResponse = await getFileInfo(
|
||||||
ddo.id,
|
asset,
|
||||||
oceanConfig.providerUri,
|
oceanConfig.providerUri,
|
||||||
newCancelToken()
|
newCancelToken()
|
||||||
)
|
)
|
||||||
fileInfoResponse && setFileMetadata(fileInfoResponse[0])
|
fileInfoResponse && setFileMetadata(fileInfoResponse[0])
|
||||||
isMounted() && setFileIsLoading(false)
|
setFileIsLoading(false)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error(error.message)
|
Logger.error(error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initFileInfo()
|
initFileInfo()
|
||||||
}, [ddo, isMounted, newCancelToken])
|
}, [ddo, isMounted, newCancelToken, values?.services])
|
||||||
|
|
||||||
// Get and set user DT balance
|
// Get and set user DT balance
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -104,6 +118,8 @@ export default function AssetActions(): ReactElement {
|
|||||||
|
|
||||||
const UseContent = isCompute ? (
|
const UseContent = isCompute ? (
|
||||||
<Compute
|
<Compute
|
||||||
|
ddo={ddo}
|
||||||
|
price={price}
|
||||||
dtBalance={dtBalance}
|
dtBalance={dtBalance}
|
||||||
file={fileMetadata}
|
file={fileMetadata}
|
||||||
fileIsLoading={fileIsLoading}
|
fileIsLoading={fileIsLoading}
|
||||||
@ -113,6 +129,7 @@ export default function AssetActions(): ReactElement {
|
|||||||
) : (
|
) : (
|
||||||
<Consume
|
<Consume
|
||||||
ddo={ddo}
|
ddo={ddo}
|
||||||
|
price={price}
|
||||||
dtBalance={dtBalance}
|
dtBalance={dtBalance}
|
||||||
isBalanceSufficient={isBalanceSufficient}
|
isBalanceSufficient={isBalanceSufficient}
|
||||||
file={fileMetadata}
|
file={fileMetadata}
|
||||||
@ -122,22 +139,24 @@ export default function AssetActions(): ReactElement {
|
|||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
const tabs = [
|
const tabs: TabsItem[] = [
|
||||||
{
|
{
|
||||||
title: 'Use',
|
title: 'Use',
|
||||||
content: UseContent
|
content: UseContent
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
price?.type === 'pool' &&
|
price?.type === 'dynamic' &&
|
||||||
tabs.push(
|
tabs.push(
|
||||||
{
|
{
|
||||||
title: 'Pool',
|
title: 'Pool',
|
||||||
content: <Pool />
|
content: <Pool />,
|
||||||
|
disabled: !price.datatoken
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Trade',
|
title: 'Trade',
|
||||||
content: <Trade />
|
content: <Trade />,
|
||||||
|
disabled: !price.datatoken
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,14 +68,14 @@ export default function EditHistory(): ReactElement {
|
|||||||
<ul className={styles.history}>
|
<ul className={styles.history}>
|
||||||
{receipts?.map((receipt) => (
|
{receipts?.map((receipt) => (
|
||||||
<li key={receipt.id} className={styles.item}>
|
<li key={receipt.id} className={styles.item}>
|
||||||
<ExplorerLink networkId={ddo.chainId} path={`/tx/${receipt.tx}`}>
|
<ExplorerLink networkId={ddo?.chainId} path={`/tx/${receipt.tx}`}>
|
||||||
edited <Time date={`${receipt.timestamp}`} relative isUnix />
|
edited <Time date={`${receipt.timestamp}`} relative isUnix />
|
||||||
</ExplorerLink>
|
</ExplorerLink>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
<li className={styles.item}>
|
<li className={styles.item}>
|
||||||
<ExplorerLink networkId={ddo.chainId} path={`/tx/${creationTx}`}>
|
<ExplorerLink networkId={ddo?.chainId} path={`/tx/${creationTx}`}>
|
||||||
published <Time date={ddo.metadata.created} relative />
|
published <Time date={ddo?.metadata?.created} relative />
|
||||||
</ExplorerLink>
|
</ExplorerLink>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -4,27 +4,28 @@ 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'
|
||||||
|
|
||||||
export default function MetaFull(): ReactElement {
|
export default function MetaFull({ ddo }: { ddo: Asset }): ReactElement {
|
||||||
const { ddo, isInPurgatory } = useAsset()
|
const { isInPurgatory } = useAsset()
|
||||||
const { type, author, algorithm } = ddo?.metadata
|
|
||||||
|
|
||||||
function DockerImage() {
|
function DockerImage() {
|
||||||
const { image, tag } = algorithm?.container
|
const { image, tag } = ddo?.metadata?.algorithm?.container
|
||||||
return <span>{`${image}:${tag}`}</span>
|
return <span>{`${image}:${tag}`}</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return ddo ? (
|
||||||
<div className={styles.metaFull}>
|
<div className={styles.metaFull}>
|
||||||
{!isInPurgatory && <MetaItem title="Data Author" content={author} />}
|
{!isInPurgatory && (
|
||||||
|
<MetaItem title="Data Author" content={ddo?.metadata?.author} />
|
||||||
|
)}
|
||||||
<MetaItem
|
<MetaItem
|
||||||
title="Owner"
|
title="Owner"
|
||||||
content={<Publisher account={ddo?.nft?.owner} />}
|
content={<Publisher account={ddo?.nft?.owner} />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{type === 'algorithm' && algorithm && (
|
{ddo?.metadata?.type === 'algorithm' && ddo?.metadata?.algorithm && (
|
||||||
<MetaItem title="Docker Image" content={<DockerImage />} />
|
<MetaItem title="Docker Image" content={<DockerImage />} />
|
||||||
)}
|
)}
|
||||||
<MetaItem title="DID" content={<code>{ddo?.id}</code>} />
|
<MetaItem title="DID" content={<code>{ddo?.id}</code>} />
|
||||||
</div>
|
</div>
|
||||||
)
|
) : null
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@ import AssetType from '@shared/AssetType'
|
|||||||
import styles from './MetaMain.module.css'
|
import styles from './MetaMain.module.css'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
|
|
||||||
export default function MetaMain(): ReactElement {
|
export default function MetaMain({ ddo }: { ddo: Asset }): ReactElement {
|
||||||
const { ddo, owner, isAssetNetwork } = useAsset()
|
const { isAssetNetwork } = useAsset()
|
||||||
const { web3ProviderInfo } = useWeb3()
|
const { web3ProviderInfo } = useWeb3()
|
||||||
|
|
||||||
const isCompute = Boolean(getServiceByName(ddo, 'compute'))
|
const isCompute = Boolean(getServiceByName(ddo, 'compute'))
|
||||||
@ -18,6 +18,9 @@ export default function MetaMain(): ReactElement {
|
|||||||
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
const blockscoutNetworks = [1287, 2021000, 2021001, 44787, 246, 1285]
|
||||||
const isBlockscoutExplorer = blockscoutNetworks.includes(ddo?.chainId)
|
const isBlockscoutExplorer = blockscoutNetworks.includes(ddo?.chainId)
|
||||||
|
|
||||||
|
const dataTokenName = ddo?.dataTokenInfo?.name
|
||||||
|
const dataTokenSymbol = ddo?.dataTokenInfo?.symbol
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.meta}>
|
<aside className={styles.meta}>
|
||||||
<header className={styles.asset}>
|
<header className={styles.asset}>
|
||||||
@ -35,16 +38,16 @@ export default function MetaMain(): ReactElement {
|
|||||||
: `token/${ddo?.services[0].datatokenAddress}`
|
: `token/${ddo?.services[0].datatokenAddress}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{`${ddo?.dataTokenInfo.name} — ${ddo?.dataTokenInfo.symbol}`}
|
{`${dataTokenName} — ${dataTokenSymbol}`}
|
||||||
</ExplorerLink>
|
</ExplorerLink>
|
||||||
|
|
||||||
{web3ProviderInfo?.name === 'MetaMask' && isAssetNetwork && (
|
{web3ProviderInfo?.name === 'MetaMask' && isAssetNetwork && (
|
||||||
<span className={styles.addWrap}>
|
<span className={styles.addWrap}>
|
||||||
<AddToken
|
<AddToken
|
||||||
address={ddo?.services[0].datatokenAddress}
|
address={ddo?.services[0].datatokenAddress}
|
||||||
symbol={ddo?.dataTokenInfo.symbol}
|
symbol={(ddo as Asset)?.dataTokenInfo?.symbol}
|
||||||
logo="https://raw.githubusercontent.com/oceanprotocol/art/main/logo/datatoken.png"
|
logo="https://raw.githubusercontent.com/oceanprotocol/art/main/logo/datatoken.png"
|
||||||
text={`Add ${ddo?.dataTokenInfo.symbol} to wallet`}
|
text={`Add ${(ddo as Asset)?.dataTokenInfo?.symbol} to wallet`}
|
||||||
className={styles.add}
|
className={styles.add}
|
||||||
minimal
|
minimal
|
||||||
/>
|
/>
|
||||||
@ -53,7 +56,7 @@ export default function MetaMain(): ReactElement {
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div className={styles.byline}>
|
<div className={styles.byline}>
|
||||||
Published By <Publisher account={owner} />
|
Published By <Publisher account={(ddo as Asset)?.nft?.owner} />
|
||||||
<p>
|
<p>
|
||||||
<Time date={ddo?.metadata.created} relative />
|
<Time date={ddo?.metadata.created} relative />
|
||||||
{ddo?.metadata.created !== ddo?.metadata.updated && (
|
{ddo?.metadata.created !== ddo?.metadata.updated && (
|
||||||
|
@ -3,7 +3,6 @@ import MetaItem from './MetaItem'
|
|||||||
import styles from './MetaSecondary.module.css'
|
import styles from './MetaSecondary.module.css'
|
||||||
import Tags from '@shared/atoms/Tags'
|
import Tags from '@shared/atoms/Tags'
|
||||||
import Button from '@shared/atoms/Button'
|
import Button from '@shared/atoms/Button'
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
|
|
||||||
const SampleButton = ({ url }: { url: string }) => (
|
const SampleButton = ({ url }: { url: string }) => (
|
||||||
<Button
|
<Button
|
||||||
@ -18,9 +17,7 @@ const SampleButton = ({ url }: { url: string }) => (
|
|||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default function MetaSecondary(): ReactElement {
|
export default function MetaSecondary({ ddo }: { ddo: Asset }): ReactElement {
|
||||||
const { ddo } = useAsset()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className={styles.metaSecondary}>
|
<aside className={styles.metaSecondary}>
|
||||||
{ddo?.metadata.links?.length > 0 && (
|
{ddo?.metadata.links?.length > 0 && (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import Markdown from '@shared/Markdown'
|
import Markdown from '@shared/Markdown'
|
||||||
import MetaFull from './MetaFull'
|
import MetaFull from './MetaFull'
|
||||||
import MetaSecondary from './MetaSecondary'
|
import MetaSecondary from './MetaSecondary'
|
||||||
@ -7,62 +7,34 @@ import { useUserPreferences } from '@context/UserPreferences'
|
|||||||
import Bookmark from './Bookmark'
|
import Bookmark from './Bookmark'
|
||||||
import { useAsset } from '@context/Asset'
|
import { useAsset } from '@context/Asset'
|
||||||
import Alert from '@shared/atoms/Alert'
|
import Alert from '@shared/atoms/Alert'
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import Edit from '../AssetActions/Edit'
|
|
||||||
import EditComputeDataset from '../AssetActions/Edit/EditComputeDataset'
|
|
||||||
import DebugOutput from '@shared/DebugOutput'
|
import DebugOutput from '@shared/DebugOutput'
|
||||||
import MetaMain from './MetaMain'
|
import MetaMain from './MetaMain'
|
||||||
import EditHistory from './EditHistory'
|
import EditHistory from './EditHistory'
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import NetworkName from '@shared/NetworkName'
|
import NetworkName from '@shared/NetworkName'
|
||||||
import content from '../../../../content/purgatory.json'
|
import content from '../../../../content/purgatory.json'
|
||||||
|
|
||||||
export default function AssetContent({ ddo }: { ddo: Asset }): ReactElement {
|
export default function AssetContent({
|
||||||
|
ddo,
|
||||||
|
price
|
||||||
|
}: {
|
||||||
|
ddo: Asset
|
||||||
|
price: BestPrice
|
||||||
|
}): ReactElement {
|
||||||
const { debug } = useUserPreferences()
|
const { debug } = useUserPreferences()
|
||||||
const { accountId } = useWeb3()
|
const { isInPurgatory, purgatoryData } = useAsset()
|
||||||
const { price, owner, isInPurgatory, purgatoryData, isAssetNetwork } =
|
|
||||||
useAsset()
|
|
||||||
const [showEdit, setShowEdit] = useState<boolean>()
|
|
||||||
const [isComputeType, setIsComputeType] = useState<boolean>(false)
|
|
||||||
const [showEditCompute, setShowEditCompute] = useState<boolean>()
|
|
||||||
const [isOwner, setIsOwner] = useState(false)
|
|
||||||
|
|
||||||
const serviceCompute = ddo.services.filter(
|
return (
|
||||||
(service) => service.type === 'compute'
|
|
||||||
)[0]
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!accountId || !owner) return
|
|
||||||
|
|
||||||
const isOwner = accountId.toLowerCase() === owner.toLowerCase()
|
|
||||||
setIsOwner(isOwner)
|
|
||||||
setIsComputeType(Boolean(serviceCompute))
|
|
||||||
}, [accountId, price, owner, ddo])
|
|
||||||
|
|
||||||
function handleEditButton() {
|
|
||||||
setShowEdit(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleEditComputeButton() {
|
|
||||||
setShowEditCompute(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
return showEdit ? (
|
|
||||||
<Edit setShowEdit={setShowEdit} isComputeType={isComputeType} />
|
|
||||||
) : showEditCompute ? (
|
|
||||||
<EditComputeDataset setShowEdit={setShowEditCompute} />
|
|
||||||
) : (
|
|
||||||
<>
|
<>
|
||||||
<div className={styles.networkWrap}>
|
<div className={styles.networkWrap}>
|
||||||
<NetworkName networkId={ddo.chainId} className={styles.network} />
|
<NetworkName networkId={ddo?.chainId} className={styles.network} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<article className={styles.grid}>
|
<article className={styles.grid}>
|
||||||
<div>
|
<div>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<MetaMain />
|
<MetaMain ddo={ddo} />
|
||||||
<Bookmark did={ddo.id} />
|
{price?.datatoken && <Bookmark did={ddo?.id} />}
|
||||||
|
|
||||||
{isInPurgatory ? (
|
{isInPurgatory ? (
|
||||||
<Alert
|
<Alert
|
||||||
@ -77,43 +49,49 @@ export default function AssetContent({ ddo }: { ddo: Asset }): ReactElement {
|
|||||||
className={styles.description}
|
className={styles.description}
|
||||||
text={ddo?.metadata.description || ''}
|
text={ddo?.metadata.description || ''}
|
||||||
/>
|
/>
|
||||||
|
<MetaSecondary ddo={ddo} />
|
||||||
<MetaSecondary />
|
|
||||||
|
|
||||||
{isOwner && isAssetNetwork && (
|
|
||||||
<div className={styles.ownerActions}>
|
|
||||||
<Button
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
onClick={handleEditButton}
|
|
||||||
>
|
|
||||||
Edit Metadata
|
|
||||||
</Button>
|
|
||||||
{serviceCompute && ddo?.metadata.type === 'dataset' && (
|
|
||||||
<>
|
|
||||||
<span className={styles.separator}>|</span>
|
|
||||||
<Button
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
onClick={handleEditComputeButton}
|
|
||||||
>
|
|
||||||
Edit Compute Settings
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<MetaFull />
|
<MetaFull ddo={ddo} />
|
||||||
<EditHistory />
|
{price?.datatoken && <EditHistory />}
|
||||||
{debug === true && <DebugOutput title="DDO" output={ddo} />}
|
{price?.datatoken && debug === true && (
|
||||||
|
<DebugOutput title="DDO" output={ddo} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.actions}>
|
<div className={styles.actions}>
|
||||||
<AssetActions />
|
<AssetActions ddo={ddo} price={price} />
|
||||||
|
|
||||||
|
{/*
|
||||||
|
TODO: restore edit actions, ideally put edit screens on new page
|
||||||
|
with own URL instead of switching out AssetContent in place.
|
||||||
|
Simple way would be modal usage
|
||||||
|
*/}
|
||||||
|
{/* {isOwner && isAssetNetwork && (
|
||||||
|
<div className={styles.ownerActions}>
|
||||||
|
<Button
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
onClick={handleEditButton}
|
||||||
|
>
|
||||||
|
Edit Metadata
|
||||||
|
</Button>
|
||||||
|
{serviceCompute && ddo?.metadata.type === 'dataset' && (
|
||||||
|
<>
|
||||||
|
<span className={styles.separator}>|</span>
|
||||||
|
<Button
|
||||||
|
style="text"
|
||||||
|
size="small"
|
||||||
|
onClick={handleEditComputeButton}
|
||||||
|
>
|
||||||
|
Edit Compute Settings
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)} */}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</>
|
</>
|
||||||
|
@ -12,7 +12,7 @@ import { transformComputeFormToServiceComputePrivacy } from '@utils/compute'
|
|||||||
import { setMinterToDispenser, setMinterToPublisher } from '@utils/freePrice'
|
import { setMinterToDispenser, setMinterToPublisher } from '@utils/freePrice'
|
||||||
import Web3Feedback from '@shared/Web3Feedback'
|
import Web3Feedback from '@shared/Web3Feedback'
|
||||||
import { getInitialValues, validationSchema } from './_constants'
|
import { getInitialValues, validationSchema } from './_constants'
|
||||||
import content from '../../../../../content/pages/editComputeDataset.json'
|
import content from '../../../../content/pages/editComputeDataset.json'
|
||||||
|
|
||||||
export default function EditComputeDataset({
|
export default function EditComputeDataset({
|
||||||
setShowEdit
|
setShowEdit
|
@ -15,7 +15,7 @@ import { publisherTrustedAlgorithm as PublisherTrustedAlgorithm } from '@oceanpr
|
|||||||
import { useSiteMetadata } from '@hooks/useSiteMetadata'
|
import { useSiteMetadata } from '@hooks/useSiteMetadata'
|
||||||
import FormActions from './FormActions'
|
import FormActions from './FormActions'
|
||||||
import { useCancelToken } from '@hooks/useCancelToken'
|
import { useCancelToken } from '@hooks/useCancelToken'
|
||||||
import { SortTermOptions } from '../../../../@types/aquarius/SearchQuery'
|
import { SortTermOptions } from '../../../@types/aquarius/SearchQuery'
|
||||||
import { getServiceByName } from '@utils/ddo'
|
import { getServiceByName } from '@utils/ddo'
|
||||||
|
|
||||||
export default function FormEditComputeDataset({
|
export default function FormEditComputeDataset({
|
@ -4,7 +4,7 @@ import { useOcean } from '@context/Ocean'
|
|||||||
import Input, { InputProps } from '@shared/FormInput'
|
import Input, { InputProps } from '@shared/FormInput'
|
||||||
import FormActions from './FormActions'
|
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: FormFieldContent[],
|
// data: FormFieldContent[],
|
@ -1,4 +1,4 @@
|
|||||||
import { secondsToString } from '@utils/ddo'
|
import { mapTimeoutStringToSeconds, secondsToString } from '@utils/ddo'
|
||||||
import { EditableMetadataLinks } from '@oceanprotocol/lib'
|
import { EditableMetadataLinks } from '@oceanprotocol/lib'
|
||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { MetadataEditForm } from './_types'
|
import { MetadataEditForm } from './_types'
|
||||||
@ -16,7 +16,7 @@ export const validationSchema = Yup.object().shape({
|
|||||||
|
|
||||||
export function getInitialValues(
|
export function getInitialValues(
|
||||||
metadata: Metadata,
|
metadata: Metadata,
|
||||||
timeout: string,
|
timeout: number,
|
||||||
price: number
|
price: number
|
||||||
): Partial<MetadataEditForm> {
|
): Partial<MetadataEditForm> {
|
||||||
return {
|
return {
|
@ -3,7 +3,7 @@ import { EditableMetadataLinks } from '@oceanprotocol/lib'
|
|||||||
export interface MetadataEditForm {
|
export interface MetadataEditForm {
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
timeout: string
|
timeout: number
|
||||||
price?: number
|
price?: number
|
||||||
links?: string | EditableMetadataLinks[]
|
links?: string | EditableMetadataLinks[]
|
||||||
author?: string
|
author?: string
|
@ -12,7 +12,7 @@ import { Logger } from '@oceanprotocol/lib'
|
|||||||
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 content from '../../../../../content/pages/edit.json'
|
import content from '../../../../content/pages/edit.json'
|
||||||
import { MetadataEditForm } from './_types'
|
import { MetadataEditForm } from './_types'
|
||||||
|
|
||||||
export default function Edit({
|
export default function Edit({
|
@ -6,7 +6,7 @@ import { useAsset } from '@context/Asset'
|
|||||||
import AssetContent from './AssetContent'
|
import AssetContent from './AssetContent'
|
||||||
|
|
||||||
export default function AssetDetails({ uri }: { uri: string }): ReactElement {
|
export default function AssetDetails({ uri }: { uri: string }): ReactElement {
|
||||||
const { ddo, title, error, isInPurgatory, loading } = useAsset()
|
const { ddo, title, error, isInPurgatory, loading, price } = useAsset()
|
||||||
const [pageTitle, setPageTitle] = useState<string>()
|
const [pageTitle, setPageTitle] = useState<string>()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -14,13 +14,12 @@ export default function AssetDetails({ uri }: { uri: string }): ReactElement {
|
|||||||
setPageTitle('Could not retrieve asset')
|
setPageTitle('Could not retrieve asset')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setPageTitle(isInPurgatory ? '' : title)
|
setPageTitle(isInPurgatory ? '' : title)
|
||||||
}, [ddo, error, isInPurgatory, title])
|
}, [ddo, error, isInPurgatory, title])
|
||||||
|
|
||||||
return ddo && pageTitle !== undefined && !loading ? (
|
return ddo && pageTitle !== undefined && !loading ? (
|
||||||
<Page title={pageTitle} uri={uri}>
|
<Page title={pageTitle} uri={uri}>
|
||||||
<AssetContent ddo={ddo} />
|
<AssetContent ddo={ddo} price={price} />
|
||||||
</Page>
|
</Page>
|
||||||
) : error ? (
|
) : error ? (
|
||||||
<Page title={pageTitle} noPageHeader uri={uri}>
|
<Page title={pageTitle} noPageHeader uri={uri}>
|
||||||
|
@ -52,7 +52,7 @@ export default function Stats({
|
|||||||
const accountPoolAdresses: string[] = []
|
const accountPoolAdresses: string[] = []
|
||||||
const assetsPrices = await getAssetsBestPrices(assets)
|
const assetsPrices = await getAssetsBestPrices(assets)
|
||||||
for (const priceInfo of assetsPrices) {
|
for (const priceInfo of assetsPrices) {
|
||||||
if (priceInfo.price.type === 'pool') {
|
if (priceInfo.price.type === 'dynamic') {
|
||||||
accountPoolAdresses.push(priceInfo.price.address.toLowerCase())
|
accountPoolAdresses.push(priceInfo.price.address.toLowerCase())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import React, { FormEvent, ReactElement, Ref, RefObject } from 'react'
|
import React, { FormEvent, ReactElement, Ref, RefObject } from 'react'
|
||||||
import { useOcean } from '@context/Ocean'
|
|
||||||
import Button from '@shared/atoms/Button'
|
import Button from '@shared/atoms/Button'
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import { FormikContextType, useFormikContext } from 'formik'
|
import { FormikContextType, useFormikContext } from 'formik'
|
||||||
import { FormPublishData } from '../_types'
|
import { FormPublishData } from '../_types'
|
||||||
import { wizardSteps } from '../_constants'
|
import { wizardSteps } from '../_constants'
|
||||||
|
import { useWeb3 } from '@context/Web3'
|
||||||
|
|
||||||
export default function Actions({
|
export default function Actions({
|
||||||
scrollToRef
|
scrollToRef
|
||||||
}: {
|
}: {
|
||||||
scrollToRef: RefObject<any>
|
scrollToRef: RefObject<any>
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { ocean, account } = useOcean()
|
const { accountId } = useWeb3()
|
||||||
const {
|
const {
|
||||||
status,
|
status,
|
||||||
values,
|
values,
|
||||||
@ -21,13 +21,13 @@ export default function Actions({
|
|||||||
|
|
||||||
function handleNext(e: FormEvent) {
|
function handleNext(e: FormEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setFieldValue('stepCurrent', values.user.stepCurrent + 1)
|
setFieldValue('user.stepCurrent', values.user.stepCurrent + 1)
|
||||||
scrollToRef.current.scrollIntoView()
|
scrollToRef.current.scrollIntoView()
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePrevious(e: FormEvent) {
|
function handlePrevious(e: FormEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setFieldValue('stepCurrent', values.user.stepCurrent - 1)
|
setFieldValue('user.stepCurrent', values.user.stepCurrent - 1)
|
||||||
scrollToRef.current.scrollIntoView()
|
scrollToRef.current.scrollIntoView()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,11 +42,7 @@ export default function Actions({
|
|||||||
Continue
|
Continue
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button type="submit" style="primary" disabled={!accountId || !isValid}>
|
||||||
type="submit"
|
|
||||||
style="primary"
|
|
||||||
disabled={!ocean || !account || !isValid}
|
|
||||||
>
|
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
import React, { ReactElement } from 'react'
|
|
||||||
import DebugOutput from '@shared/DebugOutput'
|
|
||||||
import styles from './index.module.css'
|
|
||||||
// import { transformPublishFormToMetadata } from '@utils/metadata'
|
|
||||||
import { FormPublishData } from './_types'
|
|
||||||
import { useFormikContext } from 'formik'
|
|
||||||
|
|
||||||
export default function Debug(): ReactElement {
|
|
||||||
const { values } = useFormikContext<FormPublishData>()
|
|
||||||
const ddo = {
|
|
||||||
'@context': 'https://w3id.org/did/v1'
|
|
||||||
// dataTokenInfo: {
|
|
||||||
// ...values.dataTokenOptions
|
|
||||||
// },
|
|
||||||
// service: [
|
|
||||||
// {
|
|
||||||
// index: 0,
|
|
||||||
// type: 'metadata',
|
|
||||||
// attributes: { ...transformPublishFormToMetadata(values) }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// index: 1,
|
|
||||||
// type: values.access,
|
|
||||||
// serviceEndpoint: values.providerUri,
|
|
||||||
// attributes: {}
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.grid}>
|
|
||||||
<DebugOutput title="Collected Form Values" output={values} />
|
|
||||||
<DebugOutput title="Transformed DDO Values" output={ddo} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
6
src/components/Publish/Debug/index.module.css
Normal file
6
src/components/Publish/Debug/index.module.css
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
.debug {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--spacer);
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
26
src/components/Publish/Debug/index.tsx
Normal file
26
src/components/Publish/Debug/index.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
|
import DebugOutput from '@shared/DebugOutput'
|
||||||
|
import { FormPublishData } from '../_types'
|
||||||
|
import { useFormikContext } from 'formik'
|
||||||
|
import { transformPublishFormToDdo } from '../_utils'
|
||||||
|
import styles from './index.module.css'
|
||||||
|
|
||||||
|
export default function Debug(): ReactElement {
|
||||||
|
const { values } = useFormikContext<FormPublishData>()
|
||||||
|
const [ddo, setDdo] = useState<DDO>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function makeDdo() {
|
||||||
|
const ddo = await transformPublishFormToDdo(values)
|
||||||
|
setDdo(ddo)
|
||||||
|
}
|
||||||
|
makeDdo()
|
||||||
|
}, [values])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.debug}>
|
||||||
|
<DebugOutput title="Collected Form Values" output={values} />
|
||||||
|
<DebugOutput title="Transformed DDO Values" output={ddo} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -12,32 +12,26 @@ export default function Navigation(): ReactElement {
|
|||||||
setFieldValue('user.stepCurrent', step)
|
setFieldValue('user.stepCurrent', step)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(errors)
|
const isSuccessMetadata = errors.metadata === undefined
|
||||||
|
const isSuccessServices = errors.services === undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className={styles.navigation}>
|
<nav className={styles.navigation}>
|
||||||
<ol>
|
<ol>
|
||||||
{wizardSteps.map((step) => {
|
{wizardSteps.map((step) => (
|
||||||
const isSuccessMetadata = errors.metadata === undefined
|
<li
|
||||||
const isSuccessServices = errors.services === undefined
|
key={step.title}
|
||||||
|
onClick={() => handleStepClick(step.step)}
|
||||||
return (
|
// TODO: add success class for all steps
|
||||||
<li
|
className={`${
|
||||||
key={step.title}
|
values.user.stepCurrent === step.step ? styles.current : null
|
||||||
onClick={() => handleStepClick(step.step)}
|
} ${step.step === 1 && isSuccessMetadata ? styles.success : null} ${
|
||||||
// TODO: add success class for all steps
|
step.step === 2 && isSuccessServices ? styles.success : null
|
||||||
className={`${
|
}`}
|
||||||
values.user.stepCurrent === step.step ? styles.current : null
|
>
|
||||||
} ${
|
{step.title}
|
||||||
step.step === 1 && isSuccessMetadata ? styles.success : null
|
</li>
|
||||||
} ${
|
))}
|
||||||
step.step === 2 && isSuccessServices ? styles.success : null
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{step.title}
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
)
|
)
|
||||||
|
@ -2,23 +2,15 @@
|
|||||||
font-size: var(--font-size-small);
|
font-size: var(--font-size-small);
|
||||||
margin-top: calc(var(--spacer) / 2);
|
margin-top: calc(var(--spacer) / 2);
|
||||||
margin-bottom: var(--spacer);
|
margin-bottom: var(--spacer);
|
||||||
|
margin-left: calc(var(--spacer) / -4);
|
||||||
|
margin-right: calc(var(--spacer) / -4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview header {
|
@media (min-width: 60rem) {
|
||||||
margin-bottom: var(--spacer);
|
.preview {
|
||||||
}
|
margin-left: calc(var(--spacer) * -3);
|
||||||
|
margin-right: calc(var(--spacer) * -3);
|
||||||
.metaFull {
|
}
|
||||||
display: grid;
|
|
||||||
gap: var(--spacer);
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.metaAlgorithm {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--spacer);
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
|
|
||||||
margin-bottom: var(--spacer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.previewTitle {
|
.previewTitle {
|
||||||
@ -28,33 +20,6 @@
|
|||||||
margin-bottom: calc(var(--spacer) / 2);
|
margin-bottom: calc(var(--spacer) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.title {
|
.assetTitle {
|
||||||
margin: 0;
|
margin-bottom: calc(var(--spacer) / 1.5);
|
||||||
}
|
|
||||||
|
|
||||||
.datatoken {
|
|
||||||
margin-bottom: 0;
|
|
||||||
color: var(--color-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.preview [class*='MetaItem-module--metaItem'] h3 {
|
|
||||||
margin-bottom: calc(var(--spacer) / 12);
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
position: relative;
|
|
||||||
margin-top: calc(var(--spacer) / 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0.15rem;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.asset {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 4fr;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: calc(var(--spacer) / 2);
|
|
||||||
}
|
}
|
||||||
|
@ -1,181 +1,39 @@
|
|||||||
import React, { FormEvent, ReactElement, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import Markdown from '@shared/Markdown'
|
|
||||||
import Tags from '@shared/atoms/Tags'
|
|
||||||
import MetaItem from '../../Asset/AssetContent/MetaItem'
|
|
||||||
import FileIcon from '@shared/FileIcon'
|
|
||||||
import Button from '@shared/atoms/Button'
|
|
||||||
import NetworkName from '@shared/NetworkName'
|
|
||||||
import { useWeb3 } from '@context/Web3'
|
|
||||||
import styles from './index.module.css'
|
import styles from './index.module.css'
|
||||||
import Web3Feedback from '@shared/Web3Feedback'
|
|
||||||
import { useAsset } from '@context/Asset'
|
|
||||||
import { FormPublishData } from '../_types'
|
import { FormPublishData } from '../_types'
|
||||||
import { useFormikContext } from 'formik'
|
import { useFormikContext } from 'formik'
|
||||||
|
import AssetContent from 'src/components/Asset/AssetContent'
|
||||||
function Description({ description }: { description: string }) {
|
import { transformPublishFormToDdo } from '../_utils'
|
||||||
const [fullDescription, setFullDescription] = useState<boolean>(false)
|
|
||||||
|
|
||||||
const textLimit = 500 // string.length
|
|
||||||
const descriptionDisplay =
|
|
||||||
fullDescription === true
|
|
||||||
? description
|
|
||||||
: `${description.substring(0, textLimit)}${
|
|
||||||
description.length > textLimit ? '...' : ''
|
|
||||||
}`
|
|
||||||
|
|
||||||
function handleDescriptionToggle(e: FormEvent<HTMLButtonElement>) {
|
|
||||||
e.preventDefault()
|
|
||||||
setFullDescription(!fullDescription)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.description}>
|
|
||||||
<Markdown text={descriptionDisplay} />
|
|
||||||
{description.length > textLimit && (
|
|
||||||
<Button
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
onClick={handleDescriptionToggle}
|
|
||||||
className={styles.toggle}
|
|
||||||
>
|
|
||||||
{fullDescription === true ? 'Close' : 'Expand'}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function MetaFull({ values }: { values: Partial<FormPublishData> }) {
|
|
||||||
return (
|
|
||||||
<div className={styles.metaFull}>
|
|
||||||
{Object.entries(values)
|
|
||||||
.filter(
|
|
||||||
([key, value]) =>
|
|
||||||
!(
|
|
||||||
key.includes('name') ||
|
|
||||||
key.includes('description') ||
|
|
||||||
key.includes('tags') ||
|
|
||||||
key.includes('files') ||
|
|
||||||
key.includes('links') ||
|
|
||||||
key.includes('termsAndConditions') ||
|
|
||||||
key.includes('dataTokenOptions') ||
|
|
||||||
key.includes('dockerImage') ||
|
|
||||||
key.includes('algorithmPrivacy') ||
|
|
||||||
value === undefined
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.map(([key, value]) => (
|
|
||||||
<MetaItem key={key} title={key} content={value} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function Sample({ url }: { url: string }) {
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
href={url}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
download
|
|
||||||
style="text"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
Download Sample
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Preview(): ReactElement {
|
export default function Preview(): ReactElement {
|
||||||
const { networkId } = useWeb3()
|
const [ddo, setDdo] = useState<Asset>()
|
||||||
const { isAssetNetwork } = useAsset()
|
const [price, setPrice] = useState<BestPrice>()
|
||||||
const { values } = useFormikContext<FormPublishData>()
|
const { values } = useFormikContext<FormPublishData>()
|
||||||
|
|
||||||
return (
|
useEffect(() => {
|
||||||
<div className={styles.preview}>
|
async function makeDdo() {
|
||||||
<h2 className={styles.previewTitle}>Preview</h2>
|
const ddo = await transformPublishFormToDdo(values)
|
||||||
{/* <header>
|
setDdo(ddo as Asset)
|
||||||
{networkId && <NetworkName networkId={networkId} />}
|
|
||||||
{values.name && <h3 className={styles.title}>{values.name}</h3>}
|
|
||||||
{values.dataTokenOptions?.name && (
|
|
||||||
<p
|
|
||||||
className={styles.datatoken}
|
|
||||||
>{`${values.dataTokenOptions.name} — ${values.dataTokenOptions.symbol}`}</p>
|
|
||||||
)}
|
|
||||||
{values.description && <Description description={values.description} />}
|
|
||||||
|
|
||||||
<div className={styles.asset}>
|
// dummy BestPrice to trigger certain AssetActions
|
||||||
{values.files?.length > 0 && typeof values.files !== 'string' && (
|
const price: BestPrice = {
|
||||||
<FileIcon
|
type: values.pricing.type,
|
||||||
file={values.files[0] as FileMetadata}
|
address: '0x...',
|
||||||
className={styles.file}
|
value: values.pricing.price,
|
||||||
small
|
pools: [],
|
||||||
/>
|
oceanSymbol: 'OCEAN'
|
||||||
)}
|
}
|
||||||
</div>
|
setPrice(price)
|
||||||
|
}
|
||||||
{typeof values.links !== 'string' && values.links?.length && (
|
makeDdo()
|
||||||
<Sample url={(values.links[0] as FileMetadata).url} />
|
}, [values])
|
||||||
)}
|
|
||||||
{values.tags && <Tags items={transformTags(values.tags)} />}
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<MetaFull values={values} />
|
|
||||||
{isAssetNetwork === false && (
|
|
||||||
<Web3Feedback isAssetNetwork={isAssetNetwork} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MetadataAlgorithmPreview({
|
|
||||||
values
|
|
||||||
}: {
|
|
||||||
values: Partial<FormPublishData>
|
|
||||||
}): ReactElement {
|
|
||||||
const { networkId } = useWeb3()
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.preview}>
|
<div className={styles.preview}>
|
||||||
<h2 className={styles.previewTitle}>Preview</h2>
|
<h2 className={styles.previewTitle}>Preview</h2>
|
||||||
<header>
|
|
||||||
{networkId && <NetworkName networkId={networkId} />}
|
|
||||||
{values.name && <h3 className={styles.title}>{values.name}</h3>}
|
|
||||||
{values.dataTokenOptions?.name && (
|
|
||||||
<p
|
|
||||||
className={styles.datatoken}
|
|
||||||
>{`${values.dataTokenOptions.name} — ${values.dataTokenOptions.symbol}`}</p>
|
|
||||||
)}
|
|
||||||
{values.description && <Description description={values.description} />}
|
|
||||||
|
|
||||||
<div className={styles.asset}>
|
<h3 className={styles.assetTitle}>{values.metadata.name}</h3>
|
||||||
{values.files?.length > 0 && typeof values.files !== 'string' && (
|
<AssetContent ddo={ddo} price={price} />
|
||||||
<FileIcon
|
|
||||||
file={values.files[0] as FileMetadata}
|
|
||||||
className={styles.file}
|
|
||||||
small
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{values.tags && <Tags items={transformTags(values.tags)} />}
|
|
||||||
</header>
|
|
||||||
<div className={styles.metaAlgorithm}>
|
|
||||||
{values.dockerImage && (
|
|
||||||
<MetaItem
|
|
||||||
key="dockerImage"
|
|
||||||
title="Docker Image"
|
|
||||||
content={values.dockerImage}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{values.algorithmPrivacy && (
|
|
||||||
<MetaItem
|
|
||||||
key="privateAlgorithm"
|
|
||||||
title="Private Algorithm"
|
|
||||||
content="Yes"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<MetaFull values={values} /> */}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,13 @@ export default function PricingFields(): ReactElement {
|
|||||||
function handleTabChange(tabName: string) {
|
function handleTabChange(tabName: string) {
|
||||||
const type = tabName.toLowerCase()
|
const type = tabName.toLowerCase()
|
||||||
setFieldValue('pricing.type', type)
|
setFieldValue('pricing.type', type)
|
||||||
type === 'fixed' && setFieldValue('pricing.amountDataToken', 1000)
|
type === 'dynamic' && setFieldValue('pricing.amountDataToken', 1000)
|
||||||
type === 'free' && price < 1 && setFieldValue('pricing.price', 1)
|
type === 'free' && price < 1 && setFieldValue('pricing.price', 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always update everything when price value changes
|
// Always update everything when price value changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (type === 'fixed' || type === 'free') return
|
if (type === 'dynamic' || type === 'free') return
|
||||||
|
|
||||||
const amountDataToken =
|
const amountDataToken =
|
||||||
isValidNumber(amountOcean) &&
|
isValidNumber(amountOcean) &&
|
||||||
@ -70,36 +70,8 @@ export default function PricingFields(): ReactElement {
|
|||||||
<Tabs
|
<Tabs
|
||||||
items={tabs}
|
items={tabs}
|
||||||
handleTabChange={handleTabChange}
|
handleTabChange={handleTabChange}
|
||||||
defaultIndex={type === 'fixed' ? 0 : type === 'dynamic' ? 1 : 2}
|
defaultIndex={type === 'dynamic' ? 1 : type === 'free' ? 2 : 0}
|
||||||
className={styles.pricing}
|
className={styles.pricing}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
// async function handleCreatePricing(values: PriceOptions) {
|
|
||||||
// try {
|
|
||||||
// const priceOptions = {
|
|
||||||
// ...values,
|
|
||||||
// // swapFee is tricky: to get 0.1% you need to send 0.001 as value
|
|
||||||
// swapFee: `${values.swapFee / 100}`
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const tx = await createPricing(priceOptions, ddo)
|
|
||||||
|
|
||||||
// // Pricing failed
|
|
||||||
// if (!tx || pricingError) {
|
|
||||||
// toast.error(pricingError || 'Price creation failed.')
|
|
||||||
// Logger.error(pricingError || 'Price creation failed.')
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Pricing succeeded
|
|
||||||
// setSuccess(
|
|
||||||
// `🎉 Successfully created a ${values.type} price. 🎉 Reload the page to get all updates.`
|
|
||||||
// )
|
|
||||||
// Logger.log(`Transaction: ${tx}`)
|
|
||||||
// } catch (error) {
|
|
||||||
// toast.error(error.message)
|
|
||||||
// Logger.error(error.message)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,8 @@ export const initialValues: FormPublishData = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: conditional validation
|
||||||
|
// e.g. when algo is selected, Docker image is required
|
||||||
const validationMetadata = {
|
const validationMetadata = {
|
||||||
type: Yup.string()
|
type: Yup.string()
|
||||||
.matches(/dataset|algorithm/g, { excludeEmptyString: true })
|
.matches(/dataset|algorithm/g, { excludeEmptyString: true })
|
||||||
|
@ -3,7 +3,12 @@ import { NftOptions } from '@utils/nft'
|
|||||||
import { ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
|
|
||||||
export interface FormPublishService {
|
export interface FormPublishService {
|
||||||
files: string[]
|
files: {
|
||||||
|
url: string
|
||||||
|
valid: boolean
|
||||||
|
contentLength: string
|
||||||
|
contentType: string
|
||||||
|
}[]
|
||||||
timeout: string
|
timeout: string
|
||||||
dataTokenOptions: DataTokenOptions
|
dataTokenOptions: DataTokenOptions
|
||||||
access: 'Download' | 'Compute' | string
|
access: 'Download' | 'Compute' | string
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { mapTimeoutStringToSeconds } from '@utils/ddo'
|
||||||
import { getEncryptedFileUrls } from '@utils/provider'
|
import { getEncryptedFileUrls } from '@utils/provider'
|
||||||
import { sha256 } from 'js-sha256'
|
import { sha256 } from 'js-sha256'
|
||||||
import slugify from 'slugify'
|
import slugify from 'slugify'
|
||||||
@ -27,12 +28,14 @@ function transformTags(value: string): string[] {
|
|||||||
|
|
||||||
export async function transformPublishFormToDdo(
|
export async function transformPublishFormToDdo(
|
||||||
values: FormPublishData,
|
values: FormPublishData,
|
||||||
datatokenAddress: string,
|
// Those 2 are only passed during actual publishing process
|
||||||
nftAddress: string
|
// so we can always assume if they are not passed, we are on preview.
|
||||||
|
datatokenAddress?: string,
|
||||||
|
nftAddress?: string
|
||||||
): Promise<DDO> {
|
): Promise<DDO> {
|
||||||
const { metadata, services } = values
|
const { metadata, services, user } = values
|
||||||
const { chainId, accountId } = values.user
|
const { chainId, accountId } = user
|
||||||
const did = sha256(`${nftAddress}${chainId}`)
|
const did = nftAddress ? `0x${sha256(`${nftAddress}${chainId}`)}` : '0x...'
|
||||||
const currentTime = dateToStringNoMS(new Date())
|
const currentTime = dateToStringNoMS(new Date())
|
||||||
const {
|
const {
|
||||||
type,
|
type,
|
||||||
@ -48,12 +51,12 @@ export async function transformPublishFormToDdo(
|
|||||||
} = metadata
|
} = metadata
|
||||||
const { access, files, providerUrl, timeout } = services[0]
|
const { access, files, providerUrl, timeout } = services[0]
|
||||||
|
|
||||||
const filesEncrypted = await getEncryptedFileUrls(
|
const filesTransformed = files?.length && files[0].valid && [...files[0].url]
|
||||||
files as string[],
|
|
||||||
providerUrl,
|
const filesEncrypted =
|
||||||
did,
|
files?.length &&
|
||||||
accountId
|
files[0].valid &&
|
||||||
)
|
(await getEncryptedFileUrls(filesTransformed, providerUrl, did, accountId))
|
||||||
|
|
||||||
const newMetadata: Metadata = {
|
const newMetadata: Metadata = {
|
||||||
created: currentTime,
|
created: currentTime,
|
||||||
@ -70,13 +73,13 @@ export async function transformPublishFormToDdo(
|
|||||||
},
|
},
|
||||||
...(type === 'algorithm' && {
|
...(type === 'algorithm' && {
|
||||||
algorithm: {
|
algorithm: {
|
||||||
language: getUrlFileExtension(files[0]),
|
language: files?.length ? getUrlFileExtension(filesTransformed[0]) : '',
|
||||||
version: '0.1',
|
version: '0.1',
|
||||||
container: {
|
container: {
|
||||||
entrypoint: dockerImageCustomEntrypoint,
|
entrypoint: dockerImageCustomEntrypoint,
|
||||||
image: dockerImageCustom,
|
image: dockerImageCustom,
|
||||||
tag: dockerImageCustomTag,
|
tag: dockerImageCustomTag,
|
||||||
checksum: '' // how to get? Is it user input?
|
checksum: '' // TODO: how to get? Is it user input?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -87,7 +90,7 @@ export async function transformPublishFormToDdo(
|
|||||||
files: filesEncrypted,
|
files: filesEncrypted,
|
||||||
datatokenAddress,
|
datatokenAddress,
|
||||||
serviceEndpoint: providerUrl,
|
serviceEndpoint: providerUrl,
|
||||||
timeout,
|
timeout: mapTimeoutStringToSeconds(timeout),
|
||||||
...(access === 'compute' && {
|
...(access === 'compute' && {
|
||||||
compute: {
|
compute: {
|
||||||
namespace: 'ocean-compute',
|
namespace: 'ocean-compute',
|
||||||
@ -110,7 +113,17 @@ export async function transformPublishFormToDdo(
|
|||||||
version: '4.0.0',
|
version: '4.0.0',
|
||||||
chainId,
|
chainId,
|
||||||
metadata: newMetadata,
|
metadata: newMetadata,
|
||||||
services: [newService]
|
services: [newService],
|
||||||
|
// only added for DDO preview, reflecting Asset response
|
||||||
|
...(!datatokenAddress && {
|
||||||
|
dataTokenInfo: {
|
||||||
|
name: values.services[0].dataTokenOptions.name,
|
||||||
|
symbol: values.services[0].dataTokenOptions.symbol
|
||||||
|
},
|
||||||
|
nft: {
|
||||||
|
owner: accountId
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return newDdo
|
return newDdo
|
||||||
|
@ -16,7 +16,9 @@ import { Steps } from './Steps'
|
|||||||
import { FormPublishData } from './_types'
|
import { FormPublishData } from './_types'
|
||||||
import { sha256 } from 'js-sha256'
|
import { sha256 } from 'js-sha256'
|
||||||
import { generateNftCreateData } from '@utils/nft'
|
import { generateNftCreateData } from '@utils/nft'
|
||||||
|
import { useUserPreferences } from '@context/UserPreferences'
|
||||||
|
|
||||||
|
// TODO: restore FormikPersist, add back clear form action
|
||||||
const formName = 'ocean-publish-form'
|
const formName = 'ocean-publish-form'
|
||||||
|
|
||||||
export default function PublishPage({
|
export default function PublishPage({
|
||||||
@ -24,6 +26,7 @@ export default function PublishPage({
|
|||||||
}: {
|
}: {
|
||||||
content: { title: string; description: string; warning: string }
|
content: { title: string; description: string; warning: string }
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
|
const { debug } = useUserPreferences()
|
||||||
const { accountId, chainId } = useWeb3()
|
const { accountId, chainId } = useWeb3()
|
||||||
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
const { isInPurgatory, purgatoryData } = useAccountPurgatory(accountId)
|
||||||
// const { publish, publishError, isLoading, publishStepText } = usePublish()
|
// const { publish, publishError, isLoading, publishStepText } = usePublish()
|
||||||
@ -39,6 +42,11 @@ export default function PublishPage({
|
|||||||
// const nftOptions = values.metadata.nft
|
// const nftOptions = values.metadata.nft
|
||||||
// const nftCreateData = generateNftCreateData(nftOptions)
|
// const nftCreateData = generateNftCreateData(nftOptions)
|
||||||
// const ercParams = {}
|
// const ercParams = {}
|
||||||
|
// const priceOptions = {
|
||||||
|
// ...values,
|
||||||
|
// // swapFee is tricky: to get 0.1% you need to send 0.001 as value
|
||||||
|
// swapFee: `${values.swapFee / 100}`
|
||||||
|
// }
|
||||||
// const txMint = await createNftWithErc(accountId, nftCreateData)
|
// const txMint = await createNftWithErc(accountId, nftCreateData)
|
||||||
// const { nftAddress, datatokenAddress } = txMint.logs[0].args
|
// const { nftAddress, datatokenAddress } = txMint.logs[0].args
|
||||||
//
|
//
|
||||||
@ -137,7 +145,7 @@ export default function PublishPage({
|
|||||||
<Steps />
|
<Steps />
|
||||||
<Actions scrollToRef={scrollToRef} />
|
<Actions scrollToRef={scrollToRef} />
|
||||||
</Form>
|
</Form>
|
||||||
<Debug />
|
{debug && <Debug />}
|
||||||
</>
|
</>
|
||||||
</Formik>
|
</Formik>
|
||||||
)}
|
)}
|
||||||
|
Loading…
Reference in New Issue
Block a user