OpenC3/cosmos

View on GitHub
openc3-cosmos-init/plugins/packages/openc3-cosmos-tool-cmdsender/src/tools/CommandSender/CommandParameterEditor.vue

Summary

Maintainability
Test Coverage
<!--
# Copyright 2022 Ball Aerospace & Technologies Corp.
# All Rights Reserved.
#
# This program is free software; you can modify and/or redistribute it
# under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation; version 3 with
# attribution addendums as found in the LICENSE.txt
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.

# Modified by OpenC3, Inc.
# All changes Copyright 2023, OpenC3, Inc.
# All Rights Reserved
#
# This file may also be used under the terms of a commercial license
# if purchased from OpenC3, Inc.
-->

<template>
  <div>
    <v-text-field
      v-if="states === null"
      :value="textfieldValue"
      hide-details
      dense
      @change="handleChange"
      data-test="cmd-param-value"
    />
    <v-container v-else>
      <v-row no-gutters>
        <v-col>
          <v-select
            :items="states"
            v-model="value.selected_state"
            @change="handleStateChange"
            item-text="label"
            item-value="value"
            style="primary"
            :class="stateClass()"
            hide-details
            dense
            outlined
            data-test="cmd-param-select"
          />
        </v-col>
        <v-col>
          <v-text-field
            :value="stateValue"
            @change="handleChange"
            hide-details
            dense
            data-test="cmd-param-value"
          />
        </v-col>
      </v-row>
    </v-container>
  </div>
</template>

<script>
import Utilities from '@/tools/CommandSender/utilities'

export default {
  mixins: [Utilities],
  model: {
    prop: 'initialValue',
    event: 'input',
  },
  props: {
    statesInHex: {
      type: Boolean,
      default: false,
    },
    initialValue: {
      type: Object,
      default: () => ({
        val: '',
        states: null,
        selected_state: null,
        selected_state_label: '',
        manual_value: null,
        hazardous: false,
      }),
    },
  },
  data() {
    return {
      value: this.initialValue,
    }
  },
  created() {
    this.handleChange(this.value.val)
  },
  computed: {
    textfieldValue() {
      return this.convertToString(this.value.val)
    },
    stateValue() {
      if (this.statesInHex) {
        return '0x' + this.value.val.toString(16)
      } else {
        return this.value.val
      }
    },
    states() {
      // check using != because compare with null
      if (this.value.states != null) {
        var calcStates = []
        for (var key in this.value.states) {
          if (Object.prototype.hasOwnProperty.call(this.value.states, key)) {
            calcStates.push({
              label: key,
              value: this.value.states[key].value,
              // states which are not hazardous don't have this property set so they are undefined
              hazardous: this.value.states[key].hazardous,
            })
          }
        }
        calcStates.push({
          label: 'MANUALLY ENTERED',
          value: 'MANUALLY ENTERED',
          hazardous: undefined, // see above
        })

        // TBD pick default better (use actual default instead of just first item in list)
        return calcStates
      } else {
        return null
      }
    },
  },
  methods: {
    stateClass() {
      return this.value.hazardous ? 'hazardous mr-4' : 'mr-4'
    },
    handleChange(value) {
      this.value.val = value
      this.value.manual_value = value
      if (this.value.states) {
        var selected_state = 'MANUALLY ENTERED'
        var selected_state_label = 'MANUALLY_ENTERED'
        for (const state of this.states) {
          if (state.value === parseInt(value)) {
            selected_state = parseInt(value)
            selected_state_label = state.label
            if (state.hazardous === undefined) {
              this.value.hazardous = false
            } else {
              this.value.hazardous = true
            }
            break
            // If they have ascii states the value might match the state value
          } else if (state.value === value) {
            selected_state = value
            selected_state_label = state.label
            if (state.hazardous === undefined) {
              this.value.hazardous = false
            } else {
              this.value.hazardous = true
            }
            break
          } else {
            this.value.hazardous = false
          }
        }
        this.value.selected_state = selected_state
        this.value.selected_state_label = selected_state_label
      } else {
        this.value.selected_state = null
      }
      this.$emit('input', this.value)
    },

    handleStateChange(value) {
      var selected_state_label = null
      var selected_state = null
      for (var index = 0; index < this.states.length; index++) {
        if (value === this.states[index].value) {
          if (this.states[index].hazardous === undefined) {
            this.value.hazardous = false
          } else {
            this.value.hazardous = true
          }
          selected_state_label = this.states[index].label
          selected_state = value
          break
        }
      }
      this.value.selected_state_label = selected_state_label
      if (selected_state_label === 'MANUALLY ENTERED') {
        this.value.hazardous = false
        this.value.val = this.value.manual_value
        // Stop propagation of the click event so the editor stays active
        // to let the operator enter a manual value.
        // event.originalEvent.stopPropagation()
      } else {
        this.value.val = selected_state
        this.$emit('input', this.value)
      }
    },
  },
}
</script>
<style scoped>
/* This allows Value or State selection to be wider and show state names */
.container :deep(.v-select__selections) {
  width: auto;
}
.v-overflow-btn {
  margin-top: 0px;
}
.container {
  padding: 0px;
}
.hazardous :deep(.v-select__selection) {
  color: rgb(255, 220, 0);
}
</style>