mirror of
				https://github.com/Fabio286/antares.git
				synced 2025-06-05 21:59:22 +02:00 
			
		
		
		
	Start implementing fields edit
This commit is contained in:
		| @@ -45,7 +45,7 @@ export default { | |||||||
|    computed: { |    computed: { | ||||||
|       ...mapGetters({ |       ...mapGetters({ | ||||||
|          updateStatus: 'application/getUpdateStatus', |          updateStatus: 'application/getUpdateStatus', | ||||||
|          downloadPercentage: 'application/getDownloadProgress'// TODO: remove float |          downloadPercentage: 'application/getDownloadProgress' | ||||||
|       }), |       }), | ||||||
|       updateMessage () { |       updateMessage () { | ||||||
|          switch (this.updateStatus) { |          switch (this.updateStatus) { | ||||||
|   | |||||||
| @@ -82,7 +82,6 @@ export default { | |||||||
|    }, |    }, | ||||||
|    methods: { |    methods: { | ||||||
|       ...mapActions({ |       ...mapActions({ | ||||||
|          addNotification: 'notifications/addNotification', |  | ||||||
|          addWorkspace: 'workspaces/addWorkspace', |          addWorkspace: 'workspaces/addWorkspace', | ||||||
|          connectWorkspace: 'workspaces/connectWorkspace', |          connectWorkspace: 'workspaces/connectWorkspace', | ||||||
|          removeConnected: 'workspaces/removeConnected', |          removeConnected: 'workspaces/removeConnected', | ||||||
|   | |||||||
| @@ -45,7 +45,6 @@ export default { | |||||||
|    }, |    }, | ||||||
|    methods: { |    methods: { | ||||||
|       ...mapActions({ |       ...mapActions({ | ||||||
|          addNotification: 'notifications/addNotification', |  | ||||||
|          connectWorkspace: 'workspaces/connectWorkspace' |          connectWorkspace: 'workspaces/connectWorkspace' | ||||||
|       }), |       }), | ||||||
|       async startConnection () { |       async startConnection () { | ||||||
|   | |||||||
| @@ -34,16 +34,14 @@ | |||||||
|                   :key="row._id" |                   :key="row._id" | ||||||
|                   class="tr" |                   class="tr" | ||||||
|                > |                > | ||||||
|                   <div |                   <WorkspaceQueryTableCell | ||||||
|                      v-for="(col, cKey) in row" |                      v-for="(col, cKey) in row" | ||||||
|                      :key="cKey" |                      :key="cKey" | ||||||
|                      class="td" |                      :content="col" | ||||||
|                      :class="`type-${fieldType(cKey)}${isNull(col)}`" |                      :field="cKey" | ||||||
|                      :style="{'display': cKey === '_id' ? 'none' : ''}" |                      :type="fieldType(cKey)" | ||||||
|                      tabindex="0" |                      @updateField="updateField" | ||||||
|                   > |                   /> | ||||||
|                      {{ col | typeFormat(fieldType(cKey)) }} |  | ||||||
|                   </div> |  | ||||||
|                </div> |                </div> | ||||||
|             </div> |             </div> | ||||||
|          </div> |          </div> | ||||||
| @@ -52,48 +50,16 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
| import { uidGen, mimeFromHex, formatBytes } from 'common/libs/utilities'; | import { uidGen } from 'common/libs/utilities'; | ||||||
| import hexToBinary from 'common/libs/hexToBinary'; |  | ||||||
| import moment from 'moment'; |  | ||||||
| import BaseVirtualScroll from '@/components/BaseVirtualScroll'; | import BaseVirtualScroll from '@/components/BaseVirtualScroll'; | ||||||
|  | import WorkspaceQueryTableCell from '@/components/WorkspaceQueryTableCell'; | ||||||
|  | import { mapActions } from 'vuex'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|    name: 'WorkspaceQueryTable', |    name: 'WorkspaceQueryTable', | ||||||
|    components: { |    components: { | ||||||
|       BaseVirtualScroll |       BaseVirtualScroll, | ||||||
|    }, |       WorkspaceQueryTableCell | ||||||
|    filters: { |  | ||||||
|       typeFormat (val, type) { |  | ||||||
|          if (!val) return val; |  | ||||||
|  |  | ||||||
|          switch (type) { |  | ||||||
|             case 'char': |  | ||||||
|             case 'varchar': |  | ||||||
|             case 'text': |  | ||||||
|             case 'mediumtext': |  | ||||||
|                return val.substring(0, 128); |  | ||||||
|             case 'date': |  | ||||||
|                return moment(val).format('YYYY-MM-DD'); |  | ||||||
|             case 'datetime': |  | ||||||
|             case 'timestamp': |  | ||||||
|                return moment(val).format('YYYY-MM-DD HH:mm:ss.SSS'); |  | ||||||
|             case 'blob': |  | ||||||
|             case 'mediumblob': |  | ||||||
|             case 'longblob': { |  | ||||||
|                const buff = Buffer.from(val); |  | ||||||
|                if (!buff.length) return ''; |  | ||||||
|  |  | ||||||
|                const hex = buff.toString('hex').substring(0, 8).toUpperCase(); |  | ||||||
|                return `${mimeFromHex(hex).mime} (${formatBytes(buff.length)})`; |  | ||||||
|             } |  | ||||||
|             case 'bit': { |  | ||||||
|                const hex = Buffer.from(val).toString('hex'); |  | ||||||
|                return hexToBinary(hex); |  | ||||||
|             } |  | ||||||
|             default: |  | ||||||
|                return val; |  | ||||||
|          } |  | ||||||
|       } |  | ||||||
|    }, |    }, | ||||||
|    props: { |    props: { | ||||||
|       results: Object, |       results: Object, | ||||||
| @@ -105,6 +71,11 @@ export default { | |||||||
|          localResults: [] |          localResults: [] | ||||||
|       }; |       }; | ||||||
|    }, |    }, | ||||||
|  |    computed: { | ||||||
|  |       primaryField () { | ||||||
|  |          return this.fields.filter(field => field.key === 'pri')[0] || false; | ||||||
|  |       } | ||||||
|  |    }, | ||||||
|    watch: { |    watch: { | ||||||
|       results () { |       results () { | ||||||
|          this.localResults = this.results.rows ? this.results.rows.map(item => { |          this.localResults = this.results.rows ? this.results.rows.map(item => { | ||||||
| @@ -123,6 +94,9 @@ export default { | |||||||
|       window.removeEventListener('resize', this.resizeResults); |       window.removeEventListener('resize', this.resizeResults); | ||||||
|    }, |    }, | ||||||
|    methods: { |    methods: { | ||||||
|  |       ...mapActions({ | ||||||
|  |          addNotification: 'notifications/addNotification' | ||||||
|  |       }), | ||||||
|       fieldType (cKey) { |       fieldType (cKey) { | ||||||
|          let type = 'unknown'; |          let type = 'unknown'; | ||||||
|          const field = this.fields.filter(field => field.name === cKey)[0]; |          const field = this.fields.filter(field => field.name === cKey)[0]; | ||||||
| @@ -131,9 +105,6 @@ export default { | |||||||
|  |  | ||||||
|          return type; |          return type; | ||||||
|       }, |       }, | ||||||
|       isNull (col) { |  | ||||||
|          return col === null ? ' is-null' : ''; |  | ||||||
|       }, |  | ||||||
|       keyName (key) { |       keyName (key) { | ||||||
|          switch (key) { |          switch (key) { | ||||||
|             case 'pri': |             case 'pri': | ||||||
| @@ -156,6 +127,11 @@ export default { | |||||||
|                this.resultsSize = size; |                this.resultsSize = size; | ||||||
|             } |             } | ||||||
|          } |          } | ||||||
|  |       }, | ||||||
|  |       updateField (payload) { | ||||||
|  |          if (!this.primaryField) | ||||||
|  |             this.addNotification({ status: 'warning', message: this.$t('message.unableEditFieldWithoutPrimary') }); | ||||||
|  |          console.log(payload); | ||||||
|       } |       } | ||||||
|    } |    } | ||||||
| }; | }; | ||||||
|   | |||||||
							
								
								
									
										147
									
								
								src/renderer/components/WorkspaceQueryTableCell.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								src/renderer/components/WorkspaceQueryTableCell.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  | <template> | ||||||
|  |    <div | ||||||
|  |       v-if="field !== '_id'" | ||||||
|  |       ref="cell" | ||||||
|  |       class="td" | ||||||
|  |       :class="`type-${type} p-0`" | ||||||
|  |       tabindex="0" | ||||||
|  |    > | ||||||
|  |       <span | ||||||
|  |          v-if="!isEditing" | ||||||
|  |          class="cell-content px-2" | ||||||
|  |          :class="isNull(content)" | ||||||
|  |          @dblclick="editON" | ||||||
|  |       >{{ content | typeFormat(type) }}</span> | ||||||
|  |       <input | ||||||
|  |          v-else | ||||||
|  |          ref="editField" | ||||||
|  |          v-model="localContent" | ||||||
|  |          :type="inputType" | ||||||
|  |          autofocus | ||||||
|  |          class="editable-field px-2" | ||||||
|  |          @blur="editOFF" | ||||||
|  |       > | ||||||
|  |    </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import moment from 'moment'; | ||||||
|  | import { mimeFromHex, formatBytes } from 'common/libs/utilities'; | ||||||
|  | import hexToBinary from 'common/libs/hexToBinary'; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |    name: 'WorkspaceQueryTableCell', | ||||||
|  |    filters: { | ||||||
|  |       typeFormat (val, type) { | ||||||
|  |          if (!val) return val; | ||||||
|  |  | ||||||
|  |          switch (type) { | ||||||
|  |             case 'char': | ||||||
|  |             case 'varchar': | ||||||
|  |             case 'text': | ||||||
|  |             case 'mediumtext': | ||||||
|  |                return val.substring(0, 128); | ||||||
|  |             case 'date': | ||||||
|  |                return moment(val).format('YYYY-MM-DD'); | ||||||
|  |             case 'datetime': | ||||||
|  |             case 'timestamp': | ||||||
|  |                return moment(val).format('YYYY-MM-DD HH:mm:ss.SSS'); | ||||||
|  |             case 'blob': | ||||||
|  |             case 'mediumblob': | ||||||
|  |             case 'longblob': { | ||||||
|  |                const buff = Buffer.from(val); | ||||||
|  |                if (!buff.length) return ''; | ||||||
|  |  | ||||||
|  |                const hex = buff.toString('hex').substring(0, 8).toUpperCase(); | ||||||
|  |                return `${mimeFromHex(hex).mime} (${formatBytes(buff.length)})`; | ||||||
|  |             } | ||||||
|  |             case 'bit': { | ||||||
|  |                const hex = Buffer.from(val).toString('hex'); | ||||||
|  |                return hexToBinary(hex); | ||||||
|  |             } | ||||||
|  |             default: | ||||||
|  |                return val; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |    }, | ||||||
|  |    props: { | ||||||
|  |       type: String, | ||||||
|  |       field: String, | ||||||
|  |       content: [String, Number, Object, Date, Uint8Array] | ||||||
|  |    }, | ||||||
|  |    data () { | ||||||
|  |       return { | ||||||
|  |          isEditing: false, | ||||||
|  |          localContent: '' | ||||||
|  |       }; | ||||||
|  |    }, | ||||||
|  |    computed: { | ||||||
|  |       inputType () { | ||||||
|  |          switch (this.type) { | ||||||
|  |             case 'char': | ||||||
|  |             case 'varchar': | ||||||
|  |             case 'text': | ||||||
|  |             case 'mediumtext': | ||||||
|  |                return 'text'; | ||||||
|  |             case 'int': | ||||||
|  |             case 'tinyint': | ||||||
|  |             case 'smallint': | ||||||
|  |             case 'mediumint': | ||||||
|  |                return 'number'; | ||||||
|  |             case 'date': | ||||||
|  |                return 'date'; | ||||||
|  |             case 'datetime': | ||||||
|  |             case 'timestamp': | ||||||
|  |                return 'datetime-local'; | ||||||
|  |             // TODO: file uploader/viewer or bit field | ||||||
|  |             case 'blob': | ||||||
|  |             case 'mediumblob': | ||||||
|  |             case 'longblob': | ||||||
|  |             case 'bit': | ||||||
|  |             default: | ||||||
|  |                return 'text'; | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |    }, | ||||||
|  |    methods: { | ||||||
|  |       isNull (value) { | ||||||
|  |          return value === null ? ' is-null' : ''; | ||||||
|  |       }, | ||||||
|  |       editON () { | ||||||
|  |          this.$nextTick(() => { | ||||||
|  |             this.$refs.cell.blur(); | ||||||
|  |  | ||||||
|  |             this.$nextTick(() => this.$refs.editField.focus()); | ||||||
|  |          }); | ||||||
|  |          this.localContent = this.$options.filters.typeFormat(this.content, this.type); | ||||||
|  |          this.isEditing = true; | ||||||
|  |       }, | ||||||
|  |       editOFF () { | ||||||
|  |          this.isEditing = false; | ||||||
|  |          if (this.localContent === this.content) return; | ||||||
|  |  | ||||||
|  |          const { field, localContent: content } = this; | ||||||
|  |          this.$emit('updateField', { field, content }); | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  | }; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss"> | ||||||
|  | .editable-field{ | ||||||
|  |    margin: 0; | ||||||
|  |    border: none; | ||||||
|  |    line-height: 1; | ||||||
|  |    width: 100%; | ||||||
|  |    max-width: 200px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .cell-content{ | ||||||
|  |    display: block; | ||||||
|  |    min-height: .8rem; | ||||||
|  |    text-overflow: ellipsis; | ||||||
|  |    max-width: 200px; | ||||||
|  |    white-space: nowrap; | ||||||
|  |    overflow: hidden; | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @@ -51,7 +51,8 @@ module.exports = { | |||||||
|       updateAvailable: 'Update available', |       updateAvailable: 'Update available', | ||||||
|       downloadingUpdate: 'Downloading update', |       downloadingUpdate: 'Downloading update', | ||||||
|       updateDownloaded: 'Update downloaded', |       updateDownloaded: 'Update downloaded', | ||||||
|       restartToInstall: 'Restart Antares to install' |       restartToInstall: 'Restart Antares to install', | ||||||
|  |       unableEditFieldWithoutPrimary: 'Unable to edit a field without a primary key in resultset' | ||||||
|    }, |    }, | ||||||
|    // Date and Time |    // Date and Time | ||||||
|    short: { |    short: { | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ $bg-color-gray: #272727; | |||||||
| $primary-color: #e36929; | $primary-color: #e36929; | ||||||
| $success-color: #32b643; | $success-color: #32b643; | ||||||
| $error-color: #de3b28; | $error-color: #de3b28; | ||||||
|  | $warning-color: #e0a40c; | ||||||
|  |  | ||||||
| /*Sizes*/ | /*Sizes*/ | ||||||
| $titlebar-height: 1.5rem; | $titlebar-height: 1.5rem; | ||||||
|   | |||||||
| @@ -24,7 +24,7 @@ export default { | |||||||
|       isSettingModal: state => state.is_setting_modal, |       isSettingModal: state => state.is_setting_modal, | ||||||
|       selectedSettingTab: state => state.selected_setting_tab, |       selectedSettingTab: state => state.selected_setting_tab, | ||||||
|       getUpdateStatus: state => state.update_status, |       getUpdateStatus: state => state.update_status, | ||||||
|       getDownloadProgress: state => state.download_progress |       getDownloadProgress: state => Number(state.download_progress.toFixed(1)) | ||||||
|    }, |    }, | ||||||
|    mutations: { |    mutations: { | ||||||
|       SET_LOADING_STATUS (state, payload) { |       SET_LOADING_STATUS (state, payload) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user