summaryrefslogblamecommitdiffstats
path: root/webapp/src/components/GroupModuleClientView.vue
blob: dbac06f4a262b065f47773660cb2a18967546a9d (plain) (tree)
1
2
3
4
5
6
7
8
9


         

                                 
                            


                         

                   

         

                                  
                                   


                         

                   





          
                                     






                                                

                       
                                                   

                             
                                      
                                                                                                            
                                         
                                                                                                                                                  

                                                              


                       
                                      
                                                                                                                   
                                         
                                                                                                                                 


                                                                                                   
                                                                                                           





                                                                                       

                                                                                                                                                      
                          


                        
 

                       
 
                                                   
                                  
                                                                                                                     
                                     
                                                                                                                                                                    

                                                                                                

                   
                                                                  
                                  
                                    
                                                                                     

                                                                
                                                                                   


                                                              
                          
                                                                                                               
                                                                                           
                                                            




                        
































                                                                                                                    
                       
                               
                                  
                                                                                                         
                                     
                                                                                                                                            

                                                        

                   
                               
                                  
                                                                                                        
                                     
                                                                                                                                             

                                                         

                   
                               
                                  
                                                                                                              
                                     
                                                                                                                                              

                                                          



                    




             
                                              
                                                
                                             
 

                                








                       
               

              
    

            



                        
                       

                

                
                

     
             
                                                       



                                              

                    
                                                                     

     

                                 
                                                   
                                                                 


            
                                                                                                      



                                                     
                                               


                                       
                                                                         


                           
                                        

                                                                   
       
      
                 
                                                                                       
                            

                                                 
                        
                            

                                

                           
      


                                                                                                         
                    



                                      


                                                                                                                                            



                                                                                                                   
     


                                                    





                                                                   














                                
 
 





                  

                                      
                  






                          






                      
           


                



                     
 
 




                      
 



                           


                      
 
            
                   
                    
                             


                      
 
        
<i18n>
{
  "en": {
    "name": "Name",
    "description": "Description",
    "config": "iPXE Config",
    "groups": "Groups",
    "ip": "IP Address",
    "mac": "MAC Address",
    "uuid": "UUID",
    "more": "more"
  },
  "de": {
    "name": "Name",
    "description": "Beschreibung",
    "config": "iPXE Konfiguration",
    "groups": "Gruppen",
    "ip": "IP Adresse",
    "mac": "MAC Adresse",
    "uuid": "UUID",
    "more": "mehr"
  }
}
</i18n>

<template>
  <div>
    <v-card style="margin-top: 24px">
      <div class="header-div">
        <div class="header-div-text">
          <v-icon class="mr-2">list_alt</v-icon>
          <span>Info</span>
        </div>
      </div>
      <v-divider></v-divider>
      <v-card-text>
        <v-layout wrap>
          <v-flex lg4 sm6 xs12 order-lg1 order-xs2>
            <v-layout column>
              <v-flex>
                <div class="info-box">
                  <div class="body-2 info-heading"><v-icon>label</v-icon><span>{{ $t('name') }}</span></div>
                  <div class="info-text">
                    <v-text-field v-if="editMode" class="info-input" color="primary" v-model="info.name" hide-details tabindex="1"></v-text-field>
                    <div v-else>{{ client.name || '-' }}</div>
                  </div>
                </div>
              </v-flex>
              <v-flex>
                <div class="info-box">
                  <div class="body-2 info-heading"><v-icon>device_hub</v-icon><span>{{ $t('groups') }}</span></div>
                  <div class="info-text">
                    <select-box v-if="editMode" v-model="groups" :items="groupList" class="info-input" hide-details></select-box>
                    <div v-else class="chip-container non-selectable">
                      <v-tooltip v-for="group in firstGroups" :key="group.id" top open-delay="800">
                        <template #activator="{ on }">
                          <v-chip v-on="on" small style="width: calc(50% - 8px)" @click="openGroup(group)">
                            <span class="chip-text">{{ group.name || group.id }}</span>
                          </v-chip>
                        </template>
                        <span>{{ group.name || group.id }}</span>
                      </v-tooltip>

                      <span v-if="client.groups && client.groups.length > 5" class="and-more">+ {{ client.groups.length - 5 }} {{ $t('more') }}</span>
                      <span v-else-if="client.groups === undefined || client.groups.length === 0">-</span>
                    </div>
                  </div>
                </div>
              </v-flex>

            </v-layout>
          </v-flex>

          <v-flex lg4 sm6 xs12 order-lg2 order-xs3>
            <div class="info-box">
              <div class="body-2 info-heading"><v-icon>description</v-icon><span>{{ $t('description') }}</span></div>
              <div class="info-text">
                <v-textarea v-if="editMode" class="info-input" rows="1" auto-grow hide-details color="primary" v-model="info.description" tabindex="2"></v-textarea>
                <div v-else style="white-space: pre-wrap;">{{ client.description || '-' }}</div>
              </div>
            </div>
          </v-flex>
          <v-flex lg4 xs12 order-lg3 order-xs1 class="text-right">
            <div class="info-box">
              <div v-if="!editMode">
                <v-btn color="error" text @click="deleteClient" class="info-buttons">
                  <v-icon left>delete</v-icon>{{ $t('delete') }}
                </v-btn>
                <v-btn color="primary" text @click="editInfo" class="info-buttons">
                  <v-icon left>create</v-icon>{{ $t('edit') }}
                </v-btn>
              </div>
              <div v-else>
                <v-btn color="primary" text @click="cancelEdit" class="info-buttons">{{ $t('cancel') }}</v-btn>
                <v-btn color="primary" @click="saveData" class="info-buttons" tabindex="6">
                  <v-icon left>save</v-icon>{{ $t('save') }}
                </v-btn>
              </div>
            </div>
          </v-flex>
        </v-layout>

        <v-layout>
          <v-flex :lg4="editMode" :sm6="editMode" :xs12="editMode">
            <div class="info-box">
              <div class="body-2 info-heading"><v-icon>list</v-icon><span>{{ $t('config') }}</span></div>
              <div class="info-text">
                <v-select v-if="editMode"
                  class="info-input"
                  clearable
                  item-text="name"
                  item-value="id"
                  :menu-props="{ offsetY: '' }"
                  hide-details
                  color="primary"
                  v-model="info.configId"
                  :items="configList"
                ></v-select>
                <div v-else style="display: flex">
                  <template v-for="(config, index) in client.configPath">
                    <v-icon :key="index + 'icon'" v-if="index" style="margin: 0 -6px">keyboard_arrow_left</v-icon>
                    <config-chip
                      :key="index"
                      :config="config"
                      :assigned="config.source && config.source.type === 'CLIENT' && config.source.id === client.id"
                      :active="index === 0"
                    ></config-chip>
                  </template>
                </div>
              </div>
            </div>
          </v-flex>
        </v-layout>

        <v-layout wrap>
          <v-flex lg4 sm6 xs12>
            <div class="info-box">
              <div class="body-2 info-heading"><v-icon>language</v-icon><span>{{ $t('ip') }}</span></div>
              <div class="info-text">
                <v-text-field v-if="editMode" class="info-input" color="primary" v-model="info.ip" hide-details tabindex="3"></v-text-field>
                <div v-else>{{ client.ip || '-' }}</div>
              </div>
            </div>
          </v-flex>
          <v-flex lg4 sm6 xs12>
            <div class="info-box">
              <div class="body-2 info-heading"><v-icon>memory</v-icon><span>{{ $t('mac') }}</span></div>
              <div class="info-text">
                <v-text-field v-if="editMode" class="info-input" color="primary" v-model="info.mac" hide-details tabindex="4"></v-text-field>
                <div v-else>{{ client.mac || '-' }}</div>
              </div>
            </div>
          </v-flex>
          <v-flex lg4 sm6 xs12>
            <div class="info-box">
              <div class="body-2 info-heading"><v-icon>fingerprint</v-icon><span>{{ $t('uuid') }}</span></div>
              <div class="info-text">
                <v-text-field v-if="editMode" class="info-input" color="primary" v-model="info.uuid" hide-details tabindex="5"></v-text-field>
                <div v-else>{{ client.uuid || '-' }}</div>
              </div>
            </div>
          </v-flex>
        </v-layout>
      </v-card-text>
    </v-card>
  </div>
</template>

<script>
import SelectBox from '@/components/SelectBox'
import ConfigChip from '@/components/ConfigChip'
import { mapState, mapMutations } from 'vuex'

export default {
  name: 'GroupModuleClientView',
  props: {
    client: {
      type: Object,
      default: () => {}
    },
    tabIndex: {
      type: Number
    }
  },
  components: {
    SelectBox,
    ConfigChip
  },
  data () {
    return {
      editMode: false,
      info: {
        name: '',
        description: '',
        configId: null,
        ip: '',
        mac: '',
        uuid: ''
      },
      groups: []
    }
  },
  computed: {
    ...mapState('groups', ['groupList', 'configList']),
    headers () {
      return [
        { key: 'name', text: this.$t('name') }
      ]
    },
    firstGroups () {
      return this.client.groups ? this.client.groups.slice(0, 5) : []
    }
  },
  watch: {
    client (newValue, oldValue) {
      if (newValue.id === 'create') this.editInfo()
      else if (newValue.id !== oldValue.id) this.editMode = false
    }
  },
  methods: {
    ...mapMutations('groups', ['setDialog', 'setActiveTab', 'adjustTabSlider', 'deleteFromTabChain']),
    editInfo () {
      this.editMode = true
      this.info.name = this.client.name
      this.info.description = this.client.description
      this.info.configId = this.client.configId
      this.info.ip = this.client.ip
      this.info.mac = this.client.mac
      this.info.uuid = this.client.uuid
      this.groups = this.client.groups ? this.client.groups.slice(0) : []
    },
    cancelEdit () {
      this.editMode = false
      if (this.client.id === 'create') {
        this.deleteFromTabChain({ index: this.tabIndex, count: 1 })
        this.setActiveTab(this.tabIndex - 1)
      }
    },
    saveData () {
      this.info.configId = this.info.configId === undefined ? null : this.info.configId
      this.adjustTabSlider()
      this.$store.dispatch('groups/saveClient', {
        id: this.client.id,
        data: this.info,
        groups: this.groups,
        tabIndex: this.tabIndex,
        callback: this.updateUrl
      })
      this.editMode = false
    },
    deleteClient () {
      this.setDialog({ show: true, info: { action: 'delete', type: 'client', selected: [this.client] } })
    },
    updateUrl (id) {
      this.$router.replace({
        name: 'GroupModule.client',
        params: { id, noReload: true }
      })
    },
    openGroup (group) {
      this.$store.dispatch('groups/loadGroup', { id: group.id, name: group.name, tabIndex: this.tabIndex, asParent: true, switchTab: true })
    },
    getConfigChipColor (index, config) {
      if (config.source && config.source.type === 'CLIENT' && config.source.id === this.client.id) return 'primary'
      if (index === 0) return 'success'
    }
  },
  created () {
    if (this.client.id === 'create') this.editInfo()
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.header-div {
  user-select: none;
  padding-left: 16px;
  height: 48px;
  font-weight: bold;
  display: flex;
  flex-direction: row;
  align-items: center;
}

.header-div > .header-div-text {
  flex: 1;
  display: flex;
  flex-direction: row;
  align-items: center;
}

.chip-container {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
}

.chip-container >>> .v-chip__content {
  width: 100%;
  cursor: pointer;
}

.chip-text {
  overflow: hidden;
  text-overflow: ellipsis;
}

.and-more {
  font-size: 13px;
  display: flex;
  align-items: center;
  margin: 4px 17px;
}

.info-box {
  padding: 20px;
}

.info-input {
  margin: 0;
  padding: 0 0 1px 0;
  overflow: hidden;
}

.info-heading {
  display: flex;
  align-items: center;
  margin-bottom: 10px;
}

.info-heading-button {
  margin: -2px 0 -2px 10px;
}

.info-heading > span {
  margin-left: 10px;
}

.info-text {
  overflow-x: auto;
  margin-left: 34px;
  font-family: 'Roboto Mono';
  min-height: 34px;
  display: flex;
  align-items: center;
}
</style>