github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-supply-chain-master/asset_client/src/views/property_detail.js (about)

     1  /**
     2   * Copyright 2017 Intel Corporation
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * ----------------------------------------------------------------------------
    16   */
    17  'use strict'
    18  
    19  const m = require('mithril')
    20  const _ = require('lodash')
    21  
    22  const api = require('../services/api')
    23  const payloads = require('../services/payloads')
    24  const parsing = require('../services/parsing')
    25  const transactions = require('../services/transactions')
    26  const layout = require('../components/layout')
    27  const { LineGraphWidget, MapWidget } = require('../components/data')
    28  const { Table, PagingButtons } = require('../components/tables')
    29  
    30  const PAGE_SIZE = 50
    31  
    32  const withIntVal = fn => m.withAttr('value', v => fn(parsing.toInt(v)))
    33  
    34  const typedWidget = state => {
    35    const property = _.get(state, 'property', {})
    36  
    37    if (property.dataType === 'LOCATION') {
    38      return m(MapWidget, {
    39        coordinates: property.updates.map(update => update.value)
    40      })
    41    }
    42  
    43    if (property.dataType === 'NUMBER') {
    44      return m(LineGraphWidget, { updates: property.updates })
    45    }
    46  
    47    return null
    48  }
    49  
    50  const updateSubmitter = state => e => {
    51    e.preventDefault()
    52    const { name, dataType, recordId } = state.property
    53  
    54    let value = null
    55    if (state.update) {
    56      value = state.update
    57    } else {
    58      value = state.tmp
    59    }
    60  
    61    const update = { name }
    62    update.dataType = payloads.updateProperties.enum[dataType]
    63    update[`${dataType.toLowerCase()}Value`] = value
    64  
    65    const payload = payloads.updateProperties({
    66      recordId,
    67      properties: [update]
    68    })
    69  
    70    transactions.submit(payload, true)
    71      .then(() => api.get(`records/${recordId}/${name}`))
    72      .then(property => {
    73        _.each(e.target.elements, el => { el.value = null })
    74        state.update = null
    75        state.tmp = {}
    76        property.updates.forEach(update => {
    77          update.value = parsing.floatifyValue(update.value)
    78        })
    79        state.property = property
    80      })
    81  }
    82  
    83  // Produces an input field particular to the type of data
    84  const typedInput = state => {
    85    if (state.property.dataType === 'NUMBER') {
    86      return m('.col-md-8', [
    87        m('input.form-control', {
    88          placeholder: 'Enter New Value...',
    89          oninput: withIntVal(value => { state.update = value })
    90        })
    91      ])
    92    }
    93  
    94    if (state.property.dataType === 'LOCATION') {
    95      return [
    96        m('.col.md-4.mr-1',
    97          m('input.form-control', {
    98            placeholder: 'Enter New Latitude...',
    99            oninput: withIntVal(value => { state.tmp.latitude = value })
   100          })),
   101        m('.col.md-4',
   102          m('input.form-control', {
   103            placeholder: 'Enter New Longitude...',
   104            oninput: withIntVal(value => { state.tmp.longitude = value })
   105          }))
   106      ]
   107    }
   108  
   109    return m('.col-md-8', [
   110      m('input.form-control', {
   111        placeholder: 'Enter New Value...',
   112        oninput: m.withAttr('value', value => { state.update = value })
   113      })
   114    ])
   115  }
   116  
   117  const updateForm = state => {
   118    const inputField = typedInput(state)
   119    if (!inputField) return null
   120  
   121    return m('form.my-5', {
   122      onsubmit: updateSubmitter(state)
   123    }, [
   124      m('.container',
   125        m('.row.justify-content-center',
   126          inputField,
   127          m('.col-md-2',
   128            m('button.btn.btn-primary', { type: 'submit' }, 'Update'))))
   129    ])
   130  }
   131  
   132  /**
   133   * Displays updates to a property, and form for submitting new updates.
   134   */
   135  const PropertyDetailPage = {
   136    oninit (vnode) {
   137      vnode.state.currentPage = 0
   138      vnode.state.tmp = {}
   139  
   140      const refresh = () => {
   141        api.get(`records/${vnode.attrs.recordId}/${vnode.attrs.name}`)
   142          .then(property => {
   143            property.updates.forEach(update => {
   144              update.value = parsing.floatifyValue(update.value)
   145            })
   146            vnode.state.property = property
   147          })
   148          .then(() => { vnode.state.refreshId = setTimeout(refresh, 2000) })
   149      }
   150  
   151      refresh()
   152    },
   153  
   154    onbeforeremove (vnode) {
   155      clearTimeout(vnode.state.refreshId)
   156    },
   157  
   158    view (vnode) {
   159      const name = _.capitalize(vnode.attrs.name)
   160      const record = vnode.attrs.recordId
   161  
   162      const reporters = _.get(vnode.state, 'property.reporters', [])
   163      const isReporter = reporters.includes(api.getPublicKey())
   164  
   165      const updates = _.get(vnode.state, 'property.updates', [])
   166      const page = updates.slice(vnode.state.currentPage * PAGE_SIZE,
   167                                 (vnode.state.currentPage + 1) * PAGE_SIZE)
   168  
   169      return [
   170        layout.title(`${name} of ${record}`),
   171        typedWidget(vnode.state),
   172        isReporter ? updateForm(vnode.state) : null,
   173        m('.container',
   174          layout.row([
   175            m('h5.mr-auto', 'Update History'),
   176            m(PagingButtons, {
   177              setPage: page => { vnode.state.currentPage = page },
   178              currentPage: vnode.state.currentPage,
   179              maxPage: updates.length / PAGE_SIZE
   180            })
   181          ]),
   182          m(Table, {
   183            headers: ['Value', 'Reporter', 'Time'],
   184            rows: page.map(update => {
   185              return [
   186                parsing.stringifyValue(update.value,
   187                                       vnode.state.property.dataType,
   188                                       vnode.state.property.name),
   189                update.reporter.name,
   190                parsing.formatTimestamp(update.timestamp)
   191              ]
   192            }),
   193            noRowsText: 'This property has never been updated'
   194          }))
   195      ]
   196    }
   197  }
   198  
   199  module.exports = PropertyDetailPage