This is an automated email from the ASF dual-hosted git repository. liyang pushed a commit to branch kylin5 in repository https://gitbox.apache.org/repos/asf/kylin.git
The following commit(s) were added to refs/heads/kylin5 by this push: new 93fee73901 KYLIN-5823,improve text recognition dialog of add batch dimensions 93fee73901 is described below commit 93fee7390113733c4b0c367734b953c0cc271b16 Author: huangchunyan <qingyanxiaon...@163.com> AuthorDate: Fri Apr 5 17:16:33 2024 +0800 KYLIN-5823,improve text recognition dialog of add batch dimensions --- .../RecognizeAggregateModal.vue | 208 ++++++++++++--------- .../common/RecognizeAggregateModal/handler.js | 3 +- .../common/RecognizeAggregateModal/locales.js | 10 +- .../common/RecognizeAggregateModal/store.js | 24 ++- .../studio/StudioModel/DimensionsModal/index.vue | 71 +++++-- .../studio/StudioModel/DimensionsModal/locales.js | 4 +- 6 files changed, 203 insertions(+), 117 deletions(-) diff --git a/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue b/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue index 7ca329cbbf..4ca6f00b91 100644 --- a/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue +++ b/kystudio/src/components/common/RecognizeAggregateModal/RecognizeAggregateModal.vue @@ -1,83 +1,83 @@ <template> - <el-dialog class="recognize-aggregate-modal" width="960px" - append-to-body - :title="$t('title')" - :visible="isShow" - :close-on-press-escape="false" - :close-on-click-modal="false" - :before-close="handleCancel" - @closed="handleClosed" - > - <div class="dialog-content"> - <div class="recognize-area"> - <div class="recognize-header" v-if="errorLines.length"> - <div class="result-counter"> - <span class="error">{{$tc('errorCount', errorCount, { count: errorCount })}}</span> - <el-tooltip :content="$t('repeatTip')" placement="top"> - <span class="warning">{{$tc('repeatCount', repeatCount, { count: repeatCount })}}</span> - </el-tooltip> - </div> - <div class="result-actions"> - <el-button icon-button text type="primary" size="mini" icon="el-ksd-n-icon-arrow-up-outlined" @click="handlePrevious" /><!-- - --><el-button icon-button text type="primary" size="mini" icon="el-ksd-n-icon-arrow-down-outlined" @click="handleNext" /> - </div> - </div> - <AceEditor :key="isShow" :placeholder="'123'" class="text-input" ref="editorRef" :value="form.text" @input="handleInputText" /> - <div class="actions"> - <el-tooltip placement="left"> - <div slot="content">{{$t('dexecute')}}<span class="accelerator-key">{{$t('acceleratorKey')}}</span></div> - <el-button icon-button class="recognize" size="small" type="primary" icon="el-ksd-n-icon-play-filled" :disabled="!form.text" @click="handleRecognize" /> + <el-dialog class="recognize-aggregate-modal" width="960px" + append-to-body + :title="$t('title')" + :visible="isShow" + :close-on-press-escape="false" + :close-on-click-modal="false" + :before-close="handleCancel" + @closed="handleClosed" + > + <div class="dialog-content"> + <div class="recognize-area"> + <div class="recognize-header" v-if="errorLines.length"> + <div class="result-counter"> + <span class="error">{{$tc('errorCount', errorCount, { count: errorCount })}}</span> + <el-tooltip :content="$t('repeatTip')" placement="top"> + <span class="warning">{{$tc('repeatCount', repeatCount, { count: repeatCount })}}</span> </el-tooltip> </div> - </div> - <div class="recognize-results" v-loading="loadingRecognize"> - <template v-if="form.dimensions.length"> - <div class="results-header"> - {{$tc('selectedDimensionCount', selectedDimensionCount, { count: selectedDimensionCount })}} - <template> - <span class="divide ksd-ml-8 ksd-mr-8">|</span><span>{{$t('usedDimensionCount', {count: usedDimensionCount})}}</span> - </template> - </div> - <div class="list-actions"> - <el-checkbox :key="isSelectAll" :indeterminate="isIndeterminate" :checked="isSelectAll" @change="handleSelectAll" /> - <div class="header-dimension-name">{{$t('dimensionName')}}</div> - <div class="header-data-type">{{$t('dataType')}}</div> - </div> - <RecycleScroller - class="dimension-list" - :items="dimensionList" - :item-size="37" - key-field="value" - > - <template slot-scope="{ item }"> - <div class="dimension" @click="handleCheckDimension(item)"> - <el-checkbox :key="item.isChecked" :checked="item.isChecked" @change="handleCheckDimension(item)" /> - <span class="name">{{ item.label }}</span> - <span class="data-type">{{ item.dataType }}</span> - <div v-if="item.isDisabled" class="current-used-mask" /> - </div> - </template> - </RecycleScroller> - </template> - <div class="all-dimension-error" v-else-if="isAllDimensionError"> - <i class="el-ksd-n-icon-error-circle-filled" /> - <span>{{$t('recognizeFailed')}}</span> + <div class="result-actions"> + <el-button icon-button text type="primary" size="mini" icon="el-ksd-n-icon-arrow-up-outlined" @click="handlePrevious" /><!-- + --><el-button icon-button text type="primary" size="mini" icon="el-ksd-n-icon-arrow-down-outlined" @click="handleNext" /> </div> - <EmptyData v-else :showImage="false" :content="$t('emptyText')" /> + </div> + <AceEditor :key="isShow" :placeholder="'123'" class="text-input" ref="editorRef" :value="form.text" @input="handleInputText" /> + <div class="actions"> + <el-tooltip placement="left"> + <div slot="content">{{$t('dexecute')}}<span class="accelerator-key">{{$t('acceleratorKey')}}</span></div> + <el-button icon-button class="recognize" size="small" type="primary" icon="el-ksd-n-icon-play-filled" :disabled="!form.text" @click="handleRecognize" /> + </el-tooltip> </div> </div> - <div slot="footer" class="dialog-footer ky-no-br-space"> - <el-button size="medium" @click="handleCancel"> - {{$t('kylinLang.common.cancel')}} - </el-button> - <el-button type="primary" size="medium" :disabled="!selectedDimensionCount" @click="handleSubmit"> - {{$t('kylinLang.common.save')}} - </el-button> + <div class="recognize-results" v-loading="loadingRecognize"> + <template v-if="form.dimensions.length"> + <div class="results-header"> + {{$tc('selectedDimensionCount', selectedDimensionCount, { count: selectedDimensionCount })}} + <template v-if="type !== 'TABLE_INDEX'"> + <span class="divide ksd-ml-8 ksd-mr-8">|</span><span>{{$t('usedDimensionCount', {count: usedDimensionCount})}}</span> + </template> + </div> + <div class="list-actions"> + <el-checkbox :key="isSelectAll" :indeterminate="isIndeterminate" :checked="isSelectAll" @change="handleSelectAll" /> + <div class="header-dimension-name">{{$t('dimensionName')}}</div> + <div class="header-data-type">{{$t('dataType')}}</div> + </div> + <RecycleScroller + class="dimension-list" + :items="dimensionList" + :item-size="37" + key-field="value" + > + <template slot-scope="{ item }"> + <div class="dimension" @click="handleCheckDimension(item)"> + <el-checkbox :key="item.isChecked" :checked="item.isChecked" @change="handleCheckDimension(item)" /> + <span class="name">{{ item.label }}</span> + <span class="data-type">{{ item.dataType }}</span> + <div v-if="item.isDisabled" class="current-used-mask" /> + </div> + </template> + </RecycleScroller> + </template> + <div class="all-dimension-error" v-else-if="isAllDimensionError"> + <i class="el-ksd-n-icon-error-circle-filled" /> + <span>{{$t('recognizeFailed')}}</span> + </div> + <EmptyData v-else :showImage="false" :content="$t('emptyText')" /> </div> - </el-dialog> - </template> + </div> + <div slot="footer" class="dialog-footer ky-no-br-space"> + <el-button size="medium" @click="handleCancel"> + {{$t('kylinLang.common.cancel')}} + </el-button> + <el-button type="primary" size="medium" :disabled="!selectedDimensionCount" @click="handleSubmit"> + {{$t('kylinLang.common.save')}} + </el-button> + </div> + </el-dialog> +</template> - <script> +<script> import Vue from 'vue' import AceEditor from 'vue2-ace-editor' import { Component, Watch } from 'vue-property-decorator' @@ -92,6 +92,7 @@ vuex.registerModule(['modals', 'RecognizeAggregateModal'], store) const TABLE_INDEX = 'TABLE_INDEX' + const DIMENSION = 'DIMENSION' @Component({ components: { @@ -105,6 +106,7 @@ type: state => state.type, status: state => state.status, form: state => state.form, + usedColumns: state => state.usedColumns, errors: state => state.errors, errorLines: state => state.errorLines, errorInEditor: state => state.errorInEditor, @@ -119,7 +121,7 @@ 'hierarchyItems', 'joints', 'jointItems', - 'tableIndexCols' + 'allColumns' ]) }, methods: { @@ -181,16 +183,17 @@ } get isIndeterminate () { const { selectedDimensionCount, isSelectAll } = this - return selectedDimensionCount && !isSelectAll + return selectedDimensionCount > 0 && !isSelectAll } isColumnUsedInCurrent (column) { - const { type, includes, mandatories, hierarchyItems, jointItems, tableIndexCols } = this + const { type, includes, mandatories, hierarchyItems, jointItems, usedColumns } = this switch (type) { case AGGREGATE_TYPE.INCLUDE: return includes.includes(column) case AGGREGATE_TYPE.MANDATORY: return mandatories.includes(column) case AGGREGATE_TYPE.HIERARCHY: return hierarchyItems.includes(column) case AGGREGATE_TYPE.JOINT: return jointItems.includes(column) - case TABLE_INDEX: return tableIndexCols.includes(column) + case DIMENSION: return usedColumns.find(d => d.column === column) + case TABLE_INDEX: default: return false } } @@ -213,6 +216,7 @@ joints.some(joint => joint.items.some((item, idx) => idx !== groupIdx && item === column)) // 包含维度不做判断 case AGGREGATE_TYPE.INCLUDE: + case DIMENSION: default: return false } } @@ -237,6 +241,22 @@ default: return 'Unknow Error' } } + getRecognizeColumn (columnText) { + const { type, modelDimensions, allColumns } = this + switch (type) { + case AGGREGATE_TYPE.MANDATORY: + case AGGREGATE_TYPE.HIERARCHY: + case AGGREGATE_TYPE.JOINT: + case AGGREGATE_TYPE.INCLUDE: + return modelDimensions.find(d => d.column === columnText) + case TABLE_INDEX: + return allColumns.find(d => d.column === columnText) + case DIMENSION: + return allColumns.find(d => d.column === columnText) + default: return null + } + } + setNotInModelError (column) { const { errors } = this if (!errors.notInModel.includes(column)) this.setModal({ errors: { ...errors, notInModel: [...errors.notInModel, column] } }) @@ -271,7 +291,7 @@ <div class="ace_placeholder"> <div> {this.$t('inputPlaceholder1')} - <el-tooltip + {/* <el-tooltip popperClass="recognize-aggregate-placeholder-tooltip" placement="top" > @@ -280,7 +300,7 @@ <li>{this.$t('inputPlaceholderTooltip2')}</li> </ul> <span class="how-to-use">{this.$t('inputPlaceholderTooltipTrigger')}</span> - </el-tooltip> + </el-tooltip> */} </div> <div> {this.$t('inputPlaceholder2')} @@ -322,7 +342,7 @@ } } handleRecognize () { - const { type, form, modelDimensions } = this + const { type, form } = this const dimensions = [] this.clearupErrors() let formattedText = '' @@ -330,23 +350,23 @@ for (const text of form.text.replace(/\n*/g, '').split(/,\n*/g)) { const columnText = text.trim().toLocaleUpperCase() if (columnText) { - const dimension = modelDimensions.find(d => d.column === columnText) - if (dimension) { - if (![AGGREGATE_TYPE.INCLUDE, TABLE_INDEX].includes(type) && !this.isColumnInIncludes(dimension.column)) { - this.setNotInIncludesError(dimension.column) - } else if (!this.isColumnUsedInOther(dimension.column)) { - const duplicate = dimensions.some(d => d.value === dimension.column) + const recognizeColumn = this.getRecognizeColumn(columnText) + if (recognizeColumn) { + if (![AGGREGATE_TYPE.INCLUDE, TABLE_INDEX, DIMENSION].includes(type) && !this.isColumnInIncludes(recognizeColumn.column)) { + this.setNotInIncludesError(recognizeColumn.column) + } else if (!this.isColumnUsedInOther(recognizeColumn.column)) { + const duplicate = dimensions.some(d => d.value === recognizeColumn.column) if (!duplicate) { const isFormChecked = form.dimensions.find(d => d.value === columnText)?.isChecked const isChecked = isFormChecked ?? true - const isDisabled = this.isColumnUsedInCurrent(dimension.column) - const dataType = dimension.type - dimensions.push({ value: dimension.column, label: dimension.column, isChecked, isDisabled, dataType }) + const isDisabled = this.isColumnUsedInCurrent(recognizeColumn.column) + const dataType = recognizeColumn.type ?? recognizeColumn.datatype + dimensions.push({ value: recognizeColumn.column, label: recognizeColumn.column, isChecked, isDisabled, dataType }) } else { - this.setDuplicateError(dimension.column) + this.setDuplicateError(recognizeColumn.column) } } else { - this.setUsedInOthersError(dimension.column) + this.setUsedInOthersError(recognizeColumn.column) } } else { this.setNotInModelError(columnText) @@ -394,16 +414,18 @@ } handleCancel (done) { if (typeof done === 'function') done() + this.resetModal() this.hideModal() } handleSubmit () { const { form, callback } = this callback(form.dimensions.filter(d => !d.isDisabled && d.isChecked).map(d => d.value)) + this.resetModal() this.hideModal() } } - </script> - <style lang="less"> +</script> +<style lang="less"> @import '../../../assets/styles/variables.less'; .recognize-aggregate-modal { .el-dialog { @@ -606,5 +628,5 @@ .accelerator-key { color: @text-disabled-color; } - </style> +</style> \ No newline at end of file diff --git a/kystudio/src/components/common/RecognizeAggregateModal/handler.js b/kystudio/src/components/common/RecognizeAggregateModal/handler.js index db4eb83cf2..1f98e89e8b 100644 --- a/kystudio/src/components/common/RecognizeAggregateModal/handler.js +++ b/kystudio/src/components/common/RecognizeAggregateModal/handler.js @@ -39,6 +39,7 @@ export function updatePlaceHolder (editor, renderPlaceholder) { editor.on('input', editor.$updatePlaceholder) } editor.$updatePlaceholder(editor, renderPlaceholder) + editor.focus() } } @@ -70,7 +71,7 @@ export function scrollToLineAndHighlight (editor, line) { export function searchColumnInEditor (editor, column) { const { $search: editorSearch } = editor const session = editor.getSession() - column = column.replace(/[\\$|\\/|\\^|\\?]/g, ($1) => { + column = column.replace(/[\\$|\\/|\\^|\\?|\\(|\\)|\\{|\\|\\-}|\\&|\\*|\\(|\\)]/g, ($1) => { return `\\${$1}` }) diff --git a/kystudio/src/components/common/RecognizeAggregateModal/locales.js b/kystudio/src/components/common/RecognizeAggregateModal/locales.js index c60a41ecea..aba1a18916 100644 --- a/kystudio/src/components/common/RecognizeAggregateModal/locales.js +++ b/kystudio/src/components/common/RecognizeAggregateModal/locales.js @@ -9,11 +9,11 @@ export default { repeatCount: ' | {count} duplicate | {count} duplicates', selectedDimensionCount: 'Select {count} results | Select {count} result | Select {count} results', usedDimensionCount: '{count} already exists', - inputPlaceholder1: 'Please paste the text, separated by "," to identify the selected column.', - inputPlaceholder2: 'Example: CUSTOMER.C_CUSTKEY, CUSTOMER.C_CUSTKEY', - inputPlaceholderTooltip1: 'Method 1: Enter the formula A1 & "," on a new column in Excel, enter and drag the bottom right corner of the cell to add in bulk;', - inputPlaceholderTooltip2: 'Method 2: Select all the cells that need to added in bulk, right-click and select the cell format (shortcut cmd & ctrl + 1). Select "Custom", enter English format General "," or @ "," in the type, confirm and add in bulk.', - inputPlaceholderTooltipTrigger: 'Not sure how to batch add characters?', + inputPlaceholder1: 'Please enter "table.column", separated by commas in English. If you are using the computed column, enter the "fact table.computed column".', + inputPlaceholder2: 'e.g. CUSTOMER.C_CUSTKEY1, CUSTOMER.C_CUSTKEY2', + // inputPlaceholderTooltip1: 'Method 1: Enter the formula A1 & "," on a new column in Excel, enter and drag the bottom right corner of the cell to add in bulk;', + // inputPlaceholderTooltip2: 'Method 2: Select all the cells that need to added in bulk, right-click and select the cell format (shortcut cmd & ctrl + 1). Select "Custom", enter English format General "," or @ "," in the type, confirm and add in bulk.', + // inputPlaceholderTooltipTrigger: 'Not sure how to batch add characters?', recognizeFailed: 'Recognize failed. No result, please check and try again', columnDuplicate: 'Duplicate with {column}', columnNotInModel: 'Column {column} does not exist in the current model', diff --git a/kystudio/src/components/common/RecognizeAggregateModal/store.js b/kystudio/src/components/common/RecognizeAggregateModal/store.js index 47ab670b4b..d2d2009ab0 100644 --- a/kystudio/src/components/common/RecognizeAggregateModal/store.js +++ b/kystudio/src/components/common/RecognizeAggregateModal/store.js @@ -30,6 +30,8 @@ function getInitialState () { isShow: false, model: null, aggregate: null, + allColumns: [], + usedColumns: null, type: AGGREGATE_TYPE.INCLUDE, status: ALERT_STATUS.INIT, groupIdx: null, @@ -88,9 +90,21 @@ export default { const { aggregate } = state return aggregate?.jointArray ?? [] }, - tableIndexCols (state) { - const { allColumns } = state - return allColumns.filter(c => c.isUsed).map(c => c.fullName) + allColumns (state) { + const { allColumns, type } = state + const cloneColumns = objectClone(allColumns).map((d) => { + switch (type) { + case 'TABLE_INDEX': + d.column = d.label + return d + case 'DIMENSION': + const tableAlias = d.tableName ? d.tableName : d.tableAlias + d.column = `${tableAlias}.${d.column}` + return d + default: return d + } + }) + return cloneColumns }, hierarchyItems (state) { const { aggregate, groupIdx } = state @@ -107,9 +121,9 @@ export default { }, actions: { [types.CALL_MODAL] ({ commit }, args) { - const { aggregate, type, model, allColumns = [], groupIdx = null } = args + const { aggregate, type, model, allColumns = [], groupIdx = null, usedColumns = [] } = args return new Promise(resolve => { - commit(types.SET_MODAL, { aggregate, model, type, groupIdx, allColumns, callback: resolve }) + commit(types.SET_MODAL, { aggregate, model, type, groupIdx, allColumns, usedColumns, callback: resolve }) commit(types.SHOW_MODAL) }) } diff --git a/kystudio/src/components/studio/StudioModel/DimensionsModal/index.vue b/kystudio/src/components/studio/StudioModel/DimensionsModal/index.vue index 64e98f5e18..f9c2475702 100644 --- a/kystudio/src/components/studio/StudioModel/DimensionsModal/index.vue +++ b/kystudio/src/components/studio/StudioModel/DimensionsModal/index.vue @@ -11,8 +11,11 @@ @close="isShow && handleClose(false)"> <template v-if="isFormShow"> <div class="ksd-mb-10 ksd-right"> - <el-button @click="changeSyncName">{{!syncCommentToName ? $t('syncName') : $t('resetSyncName')}}</el-button> - <el-input :placeholder="$t('searchColumn')" style="width:230px;" @input="changeSearchVal" v-model="searchChar"> + <el-tooltip placement="top" :content="$t('textRecognitionTips')"> + <el-button size="small" nobg-text icon="el-ksd-n-icon-view-outlined" @click="handleDimensionRecognize">{{ $t('textRecognition') }}</el-button> + </el-tooltip><!-- + --><el-button @click="changeSyncName">{{!syncCommentToName ? $t('syncName') : $t('resetSyncName')}}</el-button><!-- + --><el-input :placeholder="$t('searchColumn')" class="ksd-ml-8" style="width:230px;" @input="changeSearchVal" v-model="searchChar"> <i slot="prefix" class="el-input__icon el-ksd-icon-search_22"></i> </el-input> </div> @@ -349,6 +352,9 @@ vuex.registerModule(['modals', 'DimensionsModal'], store) loadDataSourceByProject: 'LOAD_DATASOURCE', saveSampleData: 'SAVE_SAMPLE_DATA' }), + ...mapActions('RecognizeAggregateModal', { + callRecognizeAggregateModal: types.CALL_MODAL + }), tableRowClassName ({row, rowIndex}, table) { return 'guide-' + table.alias + row.name } @@ -419,6 +425,44 @@ export default class DimensionsModal extends Vue { return !this.unflattenComputedColumns.includes(row.columnName) } + async handleDimensionRecognize () { + const selectedColumns = await this.callRecognizeAggregateModal({ + type: 'DIMENSION', + allColumns: this.allColumns, + usedColumns: this.getAllSelectedColumns() + }) + if (!selectedColumns.length) return + const batchRecognizeColumns = {} + selectedColumns.forEach(col => { + const [ table, column ] = col.split('.') + batchRecognizeColumns[table] = batchRecognizeColumns[table] ? [...batchRecognizeColumns[table], column] : [column] + }) + const allTables = [...this.factTable, ...this.lookupTable, this.ccTable] + allTables.forEach(t => { + const tableAlias = t.alias ? t.alias : t.columns.length && t.columns[0].tableAlias + let isTableNeedRender = false + if (batchRecognizeColumns[tableAlias]) { + batchRecognizeColumns[tableAlias].forEach(col => { + const index = indexOfObjWithSomeKey(t.columns, 'column', col) + if (index !== -1) { + this.$set(t.columns[index], 'isSelected', true) + isTableNeedRender = true + } + }) + } + if (!this.searchChar && isTableNeedRender) { + this.$nextTick(() => { + this.renderTableColumnSelected(t) + }) + } + }) + if (this.searchChar) { + this.$nextTick(() => { + this.renderTableColumnSelected(this.pagerSearchTable[0]) + }) + } + } + // 同步或撤销注释到名称 changeSyncName () { if (!this.syncCommentToName) { @@ -612,8 +656,7 @@ export default class DimensionsModal extends Vue { } return idx } - // 检测是否有重名 - checkHasSameNamedColumn () { + get allColumns () { let columns = [] for (let k = 0; k < this.factTable.length; k++) { columns = columns.concat(this.factTable[k].columns) @@ -625,33 +668,37 @@ export default class DimensionsModal extends Vue { if (this.ccTable.columns) { columns = columns.concat(this.ccTable.columns) } + return columns + } + // 检测是否有重名 + checkHasSameNamedColumn () { return () => { let hasPassValidate = true this.errorGuidList = [] - columns.forEach((col) => { + this.allColumns.forEach((col) => { this.$set(col, 'validateNameRule', false) this.$set(col, 'validateSameName', false) this.$set(col, 'validateNameMaxLen', false) this.isClickSubmit = false }) - let selectedColumns = columns.filter((col) => { + let selectedColumns = this.allColumns.filter((col) => { return col.isSelected === true }) selectedColumns.forEach((col) => { if (countObjWithSomeKey(selectedColumns, 'alias', col.alias) > 1) { hasPassValidate = false - let idx = this.getIdxBySelected(col, columns) - this.$set(columns[idx], 'validateSameName', true) + let idx = this.getIdxBySelected(col, this.allColumns) + this.$set(this.allColumns[idx], 'validateSameName', true) this.errorGuidList.push(col.guid || col.table_guid) } else if (!this.checkDimensionNameRegex(col.alias)) { hasPassValidate = false - let idx = this.getIdxBySelected(col, columns) - this.$set(columns[idx], 'validateNameRule', true) + let idx = this.getIdxBySelected(col, this.allColumns) + this.$set(this.allColumns[idx], 'validateNameRule', true) this.errorGuidList.push(col.guid || col.table_guid) } else if (col.alias.length > this.dimMeasNameMaxLength) { hasPassValidate = false - let idx = this.getIdxBySelected(col, columns) - this.$set(columns[idx], 'validateNameMaxLen', true) + let idx = this.getIdxBySelected(col, this.allColumns) + this.$set(this.allColumns[idx], 'validateNameMaxLen', true) this.errorGuidList.push(col.guid || col.table_guid) } }) diff --git a/kystudio/src/components/studio/StudioModel/DimensionsModal/locales.js b/kystudio/src/components/studio/StudioModel/DimensionsModal/locales.js index d001604ca6..cb41b64bf9 100644 --- a/kystudio/src/components/studio/StudioModel/DimensionsModal/locales.js +++ b/kystudio/src/components/studio/StudioModel/DimensionsModal/locales.js @@ -30,6 +30,8 @@ export default { lockLookupTableTip: 'Unable to use columns from this table for dimensions. Because the join relationship of this dimension table won\'t be precomputed.', useCCBylockLookupTableTip: 'Unable to use certain computed columns. Because the join relationships of related dimension tables won\'t be precomputed.', streamTips: 'For fusion model, the time partition column can’t be deleted from the dimension.', - secStorTips: 'When the tiered storage is ON, the time partition column can\'t be deleted from the dimension.' + secStorTips: 'When the tiered storage is ON, the time partition column can\'t be deleted from the dimension.', + textRecognition: 'Text Recognition', + textRecognitionTips: 'Batch selection of columns by automatic recognition of pasted text' } }