Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d13fab267f | ||
|
|
aaf406b386 | ||
|
|
39c8855f37 |
@@ -264,6 +264,31 @@ context('editor tests: ', function () {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('9 | Info dropdown shows the applied HARDREGEX/SOFTREGEX pattern', () => {
|
||||
openTableFromTree(libraryToOpenIncludes, 'mpe_x_new')
|
||||
|
||||
clickOnEdit(() => {
|
||||
cy.get('.btn.btn-sm.btn-icon.btn-outline-danger', {
|
||||
timeout: longerCommandTimeout
|
||||
}).then(() => {
|
||||
scrollGridRight()
|
||||
|
||||
openColumnDropdown('REGEX_HARD_COL')
|
||||
cy.get('.htDropdownMenu').should(($menu) => {
|
||||
expect($menu.text()).to.include('REGEX: /[\\w.]+@[\\w]+\\.[a-z]{2,}/')
|
||||
})
|
||||
cy.get('body').click(0, 0) // close menu
|
||||
|
||||
openColumnDropdown('REGEX_SOFT_COL')
|
||||
cy.get('.htDropdownMenu').should(($menu) => {
|
||||
expect($menu.text()).to.include(
|
||||
'REGEX: /[A-Z]{1,2}\\d{1,2}[A-Z]?\\s?\\d[A-Z]{2}/'
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Handsontable virtualizes columns — with 17 columns on MPE_X_NEW, only
|
||||
@@ -280,6 +305,24 @@ const scrollGridRight = () => {
|
||||
.scrollTo('right')
|
||||
}
|
||||
|
||||
// Opens a column header's dropdown menu to reach its `info` item, which
|
||||
// has a custom renderer showing NAME/LABEL/TYPE/LENGTH/FORMAT and, when the
|
||||
// column has a HARDREGEX/SOFTREGEX rule, the applied pattern. Clicking the
|
||||
// header text first selects the column - the renderer reads
|
||||
// hot.getSelected() to decide which column to describe.
|
||||
const openColumnDropdown = (headerText: string) => {
|
||||
cy.get('#hotTable .ht_clone_top .htCore thead button.changeType', {
|
||||
timeout: longerCommandTimeout
|
||||
})
|
||||
.parents('th')
|
||||
.filter((_, th) => Cypress.$(th).text().includes(headerText))
|
||||
.last()
|
||||
.as('targetHeader')
|
||||
|
||||
cy.get('@targetHeader').click()
|
||||
cy.get('@targetHeader').find('button.changeType').click({ force: true })
|
||||
}
|
||||
|
||||
// Locates a body cell by its column's header text rather than a hardcoded
|
||||
// childNodes index. Handsontable's hiddenColumns plugin (e.g. HIDDEN_COL,
|
||||
// used by several demo columns ahead of REGEX_HARD_COL/REGEX_SOFT_COL in
|
||||
|
||||
@@ -3254,7 +3254,11 @@ export class EditorComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
colName = this.hotInstance?.colToProp(selectedCol) as string
|
||||
colInfo = this.$dataFormats?.vars[colName]
|
||||
|
||||
textInfo = buildColInfoHtml(colName, colInfo)
|
||||
textInfo = buildColInfoHtml(
|
||||
colName,
|
||||
colInfo,
|
||||
this.dcValidator?.getRegexRuleValue(colName)
|
||||
)
|
||||
}
|
||||
|
||||
elem.innerHTML = textInfo
|
||||
|
||||
@@ -204,6 +204,29 @@ export class DcValidator {
|
||||
return isNaN(digits) ? undefined : digits
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RULE_VALUE of a HARDREGEX/SOFTREGEX rule on the given
|
||||
* column, for display in the column-header info dropdown. HARDREGEX wins
|
||||
* when a column has both, matching failsSoftRegex's own precedence (no
|
||||
* point surfacing the non-blocking pattern when the blocking one is what
|
||||
* actually governs the column).
|
||||
*
|
||||
* @param col column name
|
||||
*/
|
||||
getRegexRuleValue(col: string): string | undefined {
|
||||
const regexRule =
|
||||
this.dqrules.find(
|
||||
(rule: DQRule) =>
|
||||
rule.BASE_COL === col && rule.RULE_TYPE === 'HARDREGEX'
|
||||
) ??
|
||||
this.dqrules.find(
|
||||
(rule: DQRule) =>
|
||||
rule.BASE_COL === col && rule.RULE_TYPE === 'SOFTREGEX'
|
||||
)
|
||||
|
||||
return regexRule?.RULE_VALUE
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves dropdown source for given dc validation rule
|
||||
* The values comes from MPE_SELECTBOX table
|
||||
|
||||
@@ -734,6 +734,70 @@ describe('DC Validator', () => {
|
||||
).toBeFalse()
|
||||
})
|
||||
})
|
||||
|
||||
describe('14 | getRegexRuleValue (column-header info display)', () => {
|
||||
const buildValidator = (dqRules: DQRule[]) =>
|
||||
new DcValidator(
|
||||
example_sasparams,
|
||||
example_dataformats,
|
||||
example_cols,
|
||||
dqRules,
|
||||
example_dqData
|
||||
)
|
||||
|
||||
it('returns the RULE_VALUE for a HARDREGEX rule', () => {
|
||||
const dcValidator = buildValidator([
|
||||
{
|
||||
BASE_COL: 'SOME_CHAR_ANY',
|
||||
RULE_TYPE: 'HARDREGEX',
|
||||
RULE_VALUE: '^[A-Z]+$',
|
||||
X: 0
|
||||
}
|
||||
])
|
||||
|
||||
expect(dcValidator.getRegexRuleValue('SOME_CHAR_ANY')).toEqual('^[A-Z]+$')
|
||||
})
|
||||
|
||||
it('returns the RULE_VALUE for a SOFTREGEX rule', () => {
|
||||
const dcValidator = buildValidator([
|
||||
{
|
||||
BASE_COL: 'SOME_CHAR_ANY',
|
||||
RULE_TYPE: 'SOFTREGEX',
|
||||
RULE_VALUE: '/\\b(the|data)\\b/i',
|
||||
X: 0
|
||||
}
|
||||
])
|
||||
|
||||
expect(dcValidator.getRegexRuleValue('SOME_CHAR_ANY')).toEqual(
|
||||
'/\\b(the|data)\\b/i'
|
||||
)
|
||||
})
|
||||
|
||||
it('prefers HARDREGEX over SOFTREGEX when a column has both', () => {
|
||||
const dcValidator = buildValidator([
|
||||
{
|
||||
BASE_COL: 'SOME_CHAR_ANY',
|
||||
RULE_TYPE: 'HARDREGEX',
|
||||
RULE_VALUE: '^HARD$',
|
||||
X: 0
|
||||
},
|
||||
{
|
||||
BASE_COL: 'SOME_CHAR_ANY',
|
||||
RULE_TYPE: 'SOFTREGEX',
|
||||
RULE_VALUE: '^SOFT$',
|
||||
X: 0
|
||||
}
|
||||
])
|
||||
|
||||
expect(dcValidator.getRegexRuleValue('SOME_CHAR_ANY')).toEqual('^HARD$')
|
||||
})
|
||||
|
||||
it('returns undefined for a column with no regex rule', () => {
|
||||
const dcValidator = buildValidator([])
|
||||
|
||||
expect(dcValidator.getRegexRuleValue('SOME_CHAR_ANY')).toBeUndefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
/** Minimal cols[] entry — only the fields rule ordering depends on. */
|
||||
|
||||
@@ -18,4 +18,28 @@ describe('buildColInfoHtml', () => {
|
||||
'NAME: SOME_CHAR<br>LABEL: Some Character Column<br>TYPE: char<br>LENGTH: 1024<br>FORMAT: $1024.'
|
||||
)
|
||||
})
|
||||
|
||||
it('appends a REGEX line when a regex rule value is provided', () => {
|
||||
const colInfo: DataFormat = {
|
||||
label: 'Some Character Column',
|
||||
type: 'char',
|
||||
length: '1024',
|
||||
format: '$1024.'
|
||||
}
|
||||
|
||||
expect(buildColInfoHtml('SOME_CHAR', colInfo, '/^[A-Z]+$/i')).toBe(
|
||||
'NAME: SOME_CHAR<br>LABEL: Some Character Column<br>TYPE: char<br>LENGTH: 1024<br>FORMAT: $1024.<br>REGEX: /^[A-Z]+$/i'
|
||||
)
|
||||
})
|
||||
|
||||
it('omits the REGEX line when no regex rule value is provided', () => {
|
||||
const colInfo: DataFormat = {
|
||||
label: 'Some Character Column',
|
||||
type: 'char',
|
||||
length: '1024',
|
||||
format: '$1024.'
|
||||
}
|
||||
|
||||
expect(buildColInfoHtml('SOME_CHAR', colInfo)).not.toContain('REGEX:')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,9 +7,14 @@ import { DataFormat } from '../../models/sas/common/DateFormat'
|
||||
*/
|
||||
export function buildColInfoHtml(
|
||||
colName: string,
|
||||
colInfo?: DataFormat
|
||||
colInfo?: DataFormat,
|
||||
regexRuleValue?: string
|
||||
): string {
|
||||
if (!colInfo) return 'No info found'
|
||||
|
||||
return `NAME: ${colName}<br>LABEL: ${colInfo.label}<br>TYPE: ${colInfo.type}<br>LENGTH: ${colInfo.length}<br>FORMAT: ${colInfo.format}`
|
||||
let html = `NAME: ${colName}<br>LABEL: ${colInfo.label}<br>TYPE: ${colInfo.type}<br>LENGTH: ${colInfo.length}<br>FORMAT: ${colInfo.format}`
|
||||
|
||||
if (regexRuleValue) html += `<br>REGEX: ${regexRuleValue}`
|
||||
|
||||
return html
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user