1
0
mirror of https://github.com/oceanprotocol/commons.git synced 2023-03-15 18:03:00 +01:00

add job on compute asset

This commit is contained in:
mihaisc 2020-03-29 17:39:09 +03:00
parent f63077181e
commit d234717a6a
14 changed files with 403 additions and 26 deletions

View File

@ -47,7 +47,7 @@
display: inline-block; display: inline-block;
fill: currentColor; fill: currentColor;
margin-right: $spacer / 8; margin-right: $spacer / 8;
transition: .2s ease-out; transition: 0.2s ease-out;
} }
} }

View File

@ -15,7 +15,7 @@
.header { .header {
// stylelint-disable value-keyword-case // stylelint-disable value-keyword-case
composes: categoryImage; composes: categoryimage;
// stylelint-enable value-keyword-case // stylelint-enable value-keyword-case
height: 8rem; height: 8rem;
margin-top: $spacer / $line-height; margin-top: $spacer / $line-height;
@ -23,7 +23,7 @@
.dimmed { .dimmed {
// stylelint-disable value-keyword-case // stylelint-disable value-keyword-case
composes: categoryImage; composes: categoryimage;
// stylelint-enable value-keyword-case // stylelint-enable value-keyword-case
opacity: .6; opacity: .6;
} }

View File

@ -33,8 +33,8 @@
width: 1.25rem; width: 1.25rem;
height: 1.25rem; height: 1.25rem;
top: 50%; top: 50%;
margin-top: -.6rem; margin-top: -0.6rem;
fill: rgba($brand-grey-light, .7); fill: rgba($brand-grey-light, 0.7);
} }
} }
@ -50,7 +50,7 @@
padding: $spacer / 3; padding: $spacer / 3;
margin: 0; margin: 0;
border-radius: $border-radius; border-radius: $border-radius;
transition: .2s ease-out; transition: 0.2s ease-out;
min-height: 43px; min-height: 43px;
appearance: none; appearance: none;
@ -65,8 +65,8 @@
font-size: $font-size-base; font-size: $font-size-base;
color: $brand-grey-light; color: $brand-grey-light;
font-weight: $font-weight-base; font-weight: $font-weight-base;
transition: .2s ease-out; transition: 0.2s ease-out;
opacity: .7; opacity: 0.7;
} }
&[readonly], &[readonly],
@ -155,7 +155,7 @@
font-size: $font-size-small; font-size: $font-size-small;
line-height: 1.2; line-height: 1.2;
border: 2px solid $brand-grey-lighter; border: 2px solid $brand-grey-lighter;
border-radius: .2rem; border-radius: 0.2rem;
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;

View File

@ -18,7 +18,7 @@
/* yellow triangle */ /* yellow triangle */
.statusIndicatorCloseEnough { .statusIndicatorCloseEnough {
// stylelint-disable value-keyword-case // stylelint-disable value-keyword-case
composes: statusIndicator; composes: statusindicator;
// stylelint-enable value-keyword-case // stylelint-enable value-keyword-case
background: none; background: none;
width: 0; width: 0;
@ -31,7 +31,7 @@
/* green circle */ /* green circle */
.statusIndicatorActive { .statusIndicatorActive {
// stylelint-disable value-keyword-case // stylelint-disable value-keyword-case
composes: statusIndicator; composes: statusindicator;
// stylelint-enable value-keyword-case // stylelint-enable value-keyword-case
border-radius: 50%; border-radius: 50%;
background: $green; background: $green;

View File

@ -7,12 +7,12 @@ $popoverWidth: 18rem;
width: $popoverWidth; width: $popoverWidth;
padding: $spacer / 2; padding: $spacer / 2;
background: $brand-black; background: $brand-black;
border-radius: .1rem; border-radius: 0.1rem;
border: .1rem solid $brand-grey-light; border: 0.1rem solid $brand-grey-light;
box-shadow: 0 6px 16px 0 rgba($brand-black, .3); box-shadow: 0 6px 16px 0 rgba($brand-black, 0.3);
color: $brand-grey-light; color: $brand-grey-light;
font-size: $font-size-small; font-size: $font-size-small;
animation: showPopup .2s ease-in forwards; animation: showPopup 0.2s ease-in forwards;
white-space: initial; white-space: initial;
text-align: left; text-align: left;
} }
@ -28,7 +28,7 @@ $popoverWidth: 18rem;
} }
.popoverInfoline { .popoverInfoline {
border-bottom: .05rem solid $brand-grey; border-bottom: 0.05rem solid $brand-grey;
padding: $spacer / 3 0; padding: $spacer / 3 0;
&:first-child { &:first-child {

View File

@ -24,11 +24,11 @@
// stylelint-disable value-keyword-case // stylelint-disable value-keyword-case
.indicator { .indicator {
composes: statusIndicator from '../AccountStatus/Indicator.module.scss'; composes: statusindicator from '../AccountStatus/Indicator.module.scss';
} }
.indicatorActive { .indicatorActive {
composes: statusIndicatorActive from '../AccountStatus/Indicator.module.scss'; composes: statusindicatoractive from '../AccountStatus/Indicator.module.scss';
} }
// stylelint-enable value-keyword-case // stylelint-enable value-keyword-case

View File

@ -24,7 +24,7 @@
align-items: flex-start; align-items: flex-start;
text-align: left; text-align: left;
cursor: pointer; cursor: pointer;
transition: border .2s ease-out; transition: border 0.2s ease-out;
margin-bottom: $spacer; margin-bottom: $spacer;
position: relative; position: relative;

View File

@ -8,9 +8,12 @@ import styles from './AssetDetails.module.scss'
import AssetFilesDetails from './AssetFilesDetails' import AssetFilesDetails from './AssetFilesDetails'
import Report from './Report' import Report from './Report'
import Web3 from 'web3' import Web3 from 'web3'
import AssetsJob from './AssetJob'
interface AssetDetailsProps { interface AssetDetailsProps {
ocean: any
metadata: MetaData metadata: MetaData
computeMetadata?: MetaData
ddo: DDO ddo: DDO
} }
@ -30,10 +33,19 @@ const MetaFixedItem = ({ name, value }: { name: string; value: string }) => (
</li> </li>
) )
export default function AssetDetails({ metadata, ddo }: AssetDetailsProps) { export default function AssetDetails({
metadata,
ddo,
computeMetadata,
ocean
}: AssetDetailsProps) {
const { main, additionalInformation } = metadata const { main, additionalInformation } = metadata
const price = main.price && Web3.utils.fromWei(main.price.toString()) const price = main.price && Web3.utils.fromWei(main.price.toString())
console.log(computeMetadata)
const isCompute = computeMetadata ? true : false
console.log(isCompute)
const metaFixed = [ const metaFixed = [
{ {
name: 'Author', name: 'Author',
@ -120,7 +132,18 @@ export default function AssetDetails({ metadata, ddo }: AssetDetailsProps) {
</ul> </ul>
</div> </div>
<AssetFilesDetails files={main.files ? main.files : []} ddo={ddo} /> {isCompute ? (
<AssetsJob
ddo={ddo}
ocean={ocean}
computeMetadata={computeMetadata}
/>
) : (
<AssetFilesDetails
files={main.files ? main.files : []}
ddo={ddo}
/>
)}
</> </>
) )
} }

View File

@ -0,0 +1,100 @@
@import '../../../styles/variables';
.box {
margin-bottom: $spacer / 2;
background: $brand-white;
border-radius: $border-radius;
border: 1px solid $brand-grey-lighter;
padding: $spacer / 2;
}
.dataType {
padding-top: 10px;
}
.buttonWrapper {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 120px;
}
.error {
color: $red;
align-items: center;
justify-content: center;
}
.bold {
font-weight: 900;
}
.expiry {
color: $brand-grey-light;
float: right;
}
.job {
border-top: 1px solid #e2e2e2;
}
.dragndrop {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
height: 90px;
color: $brand-grey-light;
background-color: $brand-white;
}
.filleddragndrop {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
font-weight: 900;
height: 90px;
color: $brand-grey;
background-color: $brand-white;
}
.inputWrap {
margin-top: $spacer / 4;
background: $brand-gradient;
border-radius: $border-radius;
padding: 2px;
display: flex;
position: relative;
&.isFocused {
background: $brand-black;
}
> div,
> div > div {
width: 100%;
}
}
.jobButtonWrapper {
text-align: right;
margin-top: $spacer / 4;
}
.table {
margin-top: $spacer / 2;
margin-bottom: 0;
}
.spinner {
padding-bottom: 30px;
}
.jobloading {
padding-left: 23px;
}

View File

@ -0,0 +1,159 @@
import React, { ChangeEvent, useState } from 'react'
import { DDO, MetaData } from '@oceanprotocol/squid'
import Input from '../../atoms/Form/Input'
import computeOptions from '../../../data/computeOptions.json'
import styles from './AssetJob.module.scss'
import Spinner from '../../atoms/Spinner'
import Button from '../../atoms/Button'
import { messages } from './AssetFile'
import ReactDropzone from 'react-dropzone'
interface JobsProps {
ocean: any
computeMetadata?: MetaData
ddo: DDO
}
export default function AssetsJobs({ ddo, computeMetadata, ocean }: JobsProps) {
let rawAlgorithmMeta = {
rawcode: `console.log('Hello world'!)`,
format: 'docker-image',
version: '0.1',
container: {}
}
const [isJobStarting, setIsJobStarting] = useState(false)
const [step, setStep] = useState(99)
const [computeType, setComputeType] = useState('')
const [computeValue, setComputeValue] = useState({})
const [algorithmRawCode, setAlgorithmRawCode] = useState('')
const [file, setFile] = useState(null)
const onDrop = async (files: any) => {
setFile(files[0])
const fileText = await readFileContent(files[0])
setAlgorithmRawCode(fileText)
}
const handleSelectChange = (event: ChangeEvent<HTMLInputElement>) => {
const comType = event.target.value
setComputeType(comType)
const selectedComputeOption = computeOptions.find(
x => x.name === comType
)
if (selectedComputeOption !== undefined)
setComputeValue(selectedComputeOption.value)
}
const readFileContent = (file: File): Promise<string> => {
return new Promise(resolve => {
const reader = new FileReader()
reader.onload = function(e) {
resolve(reader.result as string)
}
reader.readAsText(file)
})
}
const startJob = async () => {
try {
setIsJobStarting(true)
const accounts = await ocean.accounts.list()
const ComputeOutput = {
publishAlgorithmLog: false,
publishOutput: false,
brizoAddress: ocean.config.brizoAddress,
brizoUri: ocean.config.brizoUri,
metadataUri: ocean.config.aquariusUri,
nodeUri: ocean.config.nodeUri,
owner: accounts[0].getId(),
secretStoreUri: ocean.config.secretStoreUri
}
const agreement = await ocean.compute
.order(accounts[0], ddo.id)
.next((step: number) => setStep(step))
rawAlgorithmMeta.container = computeValue
rawAlgorithmMeta.rawcode = algorithmRawCode
const status = await ocean.compute.start(
accounts[0],
agreement,
undefined,
encodeURIComponent(JSON.stringify(rawAlgorithmMeta)),
ComputeOutput
)
console.log(status)
} catch (error) {
console.error(error.message)
}
setIsJobStarting(false)
}
return (
<>
<div>
<div>
<span className={styles.bold}>New job</span>
<div className={styles.dataType}>
<Input
type="select"
name="select"
label="Select data type"
placeholder=""
value={computeType}
options={computeOptions.map(x => x.name)}
onChange={handleSelectChange}
/>
</div>
<div>
<div className={styles.inputWrap}>
<ReactDropzone
onDrop={acceptedFiles => onDrop(acceptedFiles)}
>
{({ getRootProps, getInputProps }) => (
<div {...getRootProps()}>
<input {...getInputProps()} />
{file === null && (
<div className={styles.dragndrop}>
Click or drop your notebook here
</div>
)}
{file !== null && (
<div
className={
styles.filleddragndrop
}
>
You selected:{' '}
{(file as any).path}
</div>
)}
</div>
)}
</ReactDropzone>
</div>
<div className={styles.jobButtonWrapper}>
<Button
primary
onClick={() => startJob()}
disabled={
isJobStarting ||
file === null ||
computeType === ''
}
name="Purchase access"
>
Start job
</Button>
</div>
</div>
{isJobStarting ? <Spinner message={messages[step]} /> : ''}
</div>
</div>
</>
)
}

View File

@ -20,8 +20,10 @@ interface AssetProps {
} }
interface AssetState { interface AssetState {
ocean: any
ddo: DDO ddo: DDO
metadata: MetaData metadata: MetaData
computeMetadata?: MetaData
error: string error: string
isLoading: boolean isLoading: boolean
} }
@ -30,8 +32,10 @@ class Asset extends Component<AssetProps, AssetState> {
public static contextType = User public static contextType = User
public state = { public state = {
ocean: undefined,
ddo: ({} as any) as DDO, ddo: ({} as any) as DDO,
metadata: ({ main: { name: '' } } as any) as MetaData, metadata: ({ main: { name: '' } } as any) as MetaData,
computeMetadata: undefined,
error: '', error: '',
isLoading: true isLoading: true
} }
@ -44,10 +48,19 @@ class Asset extends Component<AssetProps, AssetState> {
try { try {
const { ocean } = this.context const { ocean } = this.context
const ddo = await ocean.assets.resolve(this.props.match.params.did) const ddo = await ocean.assets.resolve(this.props.match.params.did)
const { attributes } = ddo.findServiceByType('metadata') const { attributes } = ddo.findServiceByType('metadata')
let computeAttributes
try {
computeAttributes = ddo.findServiceByType('compute')
} catch (error) {}
this.setState({ this.setState({
ocean,
ddo, ddo,
metadata: attributes, metadata: attributes,
computeMetadata: computeAttributes,
isLoading: false isLoading: false
}) })
} catch (error) { } catch (error) {
@ -59,7 +72,14 @@ class Asset extends Component<AssetProps, AssetState> {
} }
public render() { public render() {
const { metadata, ddo, error, isLoading } = this.state const {
metadata,
ddo,
error,
isLoading,
computeMetadata,
ocean
} = this.state
const { main, additionalInformation } = metadata const { main, additionalInformation } = metadata
const hasError = error !== '' const hasError = error !== ''
@ -88,7 +108,12 @@ class Asset extends Component<AssetProps, AssetState> {
} }
> >
<Content> <Content>
<AssetDetails metadata={metadata} ddo={ddo} /> <AssetDetails
metadata={metadata}
ddo={ddo}
computeMetadata={computeMetadata}
ocean={ocean}
/>
</Content> </Content>
</Route> </Route>
) )

View File

@ -0,0 +1,18 @@
[
{
"name": "nodejs",
"value": {
"entrypoint": "node $ALGO",
"image": "node",
"tag": "10"
}
},
{
"name": "pyhton3.6",
"value": {
"entrypoint": "python3.6 $ALGO",
"image": "python",
"tag": "3.6"
}
}
]

View File

@ -11,6 +11,16 @@
"required": true, "required": true,
"help": "Enter a concise title. You will be able to enter a more thorough description in the next step." "help": "Enter a concise title. You will be able to enter a more thorough description in the next step."
}, },
"datasetType":{
"label": "Dataset type",
"help": "Pick the type which best fits your data set.",
"type": "select",
"required": true,
"options": [
"access",
"compute"
]
},
"files": { "files": {
"label": "Files", "label": "Files",
"placeholder": "e.g. https://file.com/file.json", "placeholder": "e.g. https://file.com/file.json",

View File

@ -14,7 +14,7 @@ import Content from '../../components/atoms/Content'
import withTracker from '../../hoc/withTracker' import withTracker from '../../hoc/withTracker'
type AssetType = 'dataset' | 'algorithm' | 'container' | 'workflow' | 'other' type AssetType = 'dataset' | 'algorithm' | 'container' | 'workflow' | 'other'
type DatasetType = 'compute' | 'access'
interface PublishState { interface PublishState {
name?: string name?: string
dateCreated?: string dateCreated?: string
@ -26,6 +26,7 @@ interface PublishState {
type?: AssetType type?: AssetType
copyrightHolder?: string copyrightHolder?: string
categories?: string categories?: string
datasetType?: DatasetType
currentStep?: number currentStep?: number
publishingStep?: number publishingStep?: number
@ -60,6 +61,7 @@ class Publish extends Component<{}, PublishState> {
license: '', license: '',
copyrightHolder: '', copyrightHolder: '',
categories: '', categories: '',
datasetType: 'access' as DatasetType,
currentStep: 1, currentStep: 1,
isPublishing: false, isPublishing: false,
@ -133,7 +135,8 @@ class Publish extends Component<{}, PublishState> {
isPublishing: false, isPublishing: false,
isPublished: false, isPublished: false,
publishingStep: 0, publishingStep: 0,
currentStep: 1 currentStep: 1,
datasetType: 'access' as DatasetType
}) })
} }
@ -256,6 +259,32 @@ class Publish extends Component<{}, PublishState> {
} }
} }
private async createComputeService(
ocean: any,
publisher: any,
price: string,
datePublished: string
) {
const { templates } = ocean.keeper
const serviceAgreementTemplate = await templates.escrowComputeExecutionTemplate.getServiceAgreementTemplate()
const name = 'dataAssetComputingServiceAgreement'
return {
type: 'compute',
serviceEndpoint: ocean.brizo.getComputeEndpoint(),
templateId: templates.escrowComputeExecutionTemplate.getId(),
attributes: {
main: {
creator: publisher.getId(),
datePublished,
price,
timeout: 3600,
name
},
serviceAgreementTemplate
}
}
}
private handleRegisterAsset = async (event: FormEvent<HTMLFormElement>) => { private handleRegisterAsset = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault() event.preventDefault()
@ -305,8 +334,21 @@ class Publish extends Component<{}, PublishState> {
} }
try { try {
let computeService: any[] = []
console.log('dataset type ', this.state.datasetType)
if (this.state.datasetType === 'compute') {
const service = await this.createComputeService(
ocean,
account[0],
this.state.price,
this.state.dateCreated
)
computeService = [service]
console.log('compute ', computeService)
}
const asset = await this.context.ocean.assets const asset = await this.context.ocean.assets
.create(newAsset, account[0]) .create(newAsset, account[0], computeService)
.next((publishingStep: number) => .next((publishingStep: number) =>
this.setState({ publishingStep }) this.setState({ publishingStep })
) )