mirror of https://github.com/abpframework/abp.git
Browse Source
Added navigation property auto complete combobox for the extra propertiespull/6415/head
committed by
GitHub
13 changed files with 466 additions and 88 deletions
@ -0,0 +1,37 @@ |
|||
// https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Utilities/StringUtils.cs#L155
|
|||
export function jsonNetCamelCase(str: string) { |
|||
if (!str || !isUpperCase(str[0])) return str; |
|||
|
|||
const chars = str.split(''); |
|||
const { length } = chars; |
|||
|
|||
for (let i = 0; i < length; i++) { |
|||
if (i === 1 && !isUpperCase(chars[i])) break; |
|||
|
|||
const hasNext = i + 1 < length; |
|||
|
|||
if (i > 0 && hasNext && !isUpperCase(chars[i + 1])) { |
|||
if (isSeparator(chars[i + 1])) { |
|||
chars[i] = toLowerCase(chars[i]); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
chars[i] = toLowerCase(chars[i]); |
|||
} |
|||
|
|||
return chars.join(''); |
|||
} |
|||
|
|||
function isSeparator(str = '') { |
|||
return /[\s\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,\-.\/:;<=>?@\[\]^_`{|}~]+/.test(str); |
|||
} |
|||
|
|||
function isUpperCase(str = '') { |
|||
return /[A-Z]+/.test(str); |
|||
} |
|||
|
|||
function toLowerCase(str = '') { |
|||
return str.toLowerCase(); |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
import { ABP, ExtensionPropertyUiLookupDto, RestService } from '@abp/ng.core'; |
|||
import { Observable, of } from 'rxjs'; |
|||
import { map } from 'rxjs/operators'; |
|||
import { ePropType } from '../enums/props.enum'; |
|||
import { PropCallback } from '../models/props'; |
|||
|
|||
export function createTypeaheadOptions( |
|||
lookup: ExtensionPropertyUiLookupDto, |
|||
): PropCallback<any, Observable<ABP.Option<any>[]>> { |
|||
return (data, searchText) => |
|||
searchText |
|||
? data |
|||
.getInjected(RestService) |
|||
.request( |
|||
{ |
|||
method: 'GET', |
|||
url: lookup.url, |
|||
params: { |
|||
[lookup.filterParamName]: searchText, |
|||
}, |
|||
}, |
|||
{ apiName: 'Default' }, |
|||
) |
|||
.pipe( |
|||
map(response => { |
|||
const list = response[lookup.resultListPropertyName]; |
|||
const mapToOption = (item: any) => ({ |
|||
key: item[lookup.displayPropertyName], |
|||
value: item[lookup.valuePropertyName], |
|||
}); |
|||
return list.map(mapToOption); |
|||
}), |
|||
) |
|||
: of([]); |
|||
} |
|||
|
|||
export function getTypeaheadType(lookup: ExtensionPropertyUiLookupDto, name: string) { |
|||
return Boolean(lookup.url) |
|||
? ePropType.Typeahead |
|||
: name.endsWith('_Text') |
|||
? ePropType.Hidden |
|||
: undefined; |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
import { jsonNetCamelCase } from '../lib/utils/case.util'; |
|||
|
|||
describe('Case Utils', () => { |
|||
describe('#jsonNetCamelCase', () => { |
|||
test.each` |
|||
input | output |
|||
${'Primary'} | ${'primary'} |
|||
${'PrimaryRole'} | ${'primaryRole'} |
|||
${'Primary Role'} | ${'primary Role'} |
|||
${'PrimaryRole_Text'} | ${'primaryRole_Text'} |
|||
${'ISBN'} | ${'isbn'} |
|||
${''} | ${''} |
|||
${'iMDB'} | ${'iMDB'} |
|||
`('should return $output when input is $input', ({ input, output }) => {
|
|||
expect(jsonNetCamelCase(input)).toBe(output); |
|||
}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,72 @@ |
|||
import { ExtensionPropertyUiLookupDto } from '@abp/ng.core'; |
|||
import { of } from 'rxjs'; |
|||
import { createTypeaheadOptions } from '../lib/utils/typeahead.util'; |
|||
|
|||
const lookup: ExtensionPropertyUiLookupDto = { |
|||
url: 'url', |
|||
resultListPropertyName: 'list', |
|||
displayPropertyName: 'text', |
|||
valuePropertyName: 'id', |
|||
filterParamName: 'filter', |
|||
}; |
|||
|
|||
describe('Typeahead Utils', () => { |
|||
describe('#createTypeaheadOptions', () => { |
|||
it('should return observable empty array when search text does not exist', async () => { |
|||
const list = await createTypeaheadOptions(null)(null, null).toPromise(); |
|||
expect(list).toEqual([]); |
|||
}); |
|||
|
|||
it('should call request method of RestService with lookup url, filter param and search text', async () => { |
|||
const data = createData([]); |
|||
const service = data.getInjected(); |
|||
await createTypeaheadOptions(lookup)(data, 'x').toPromise(); |
|||
expect(service.request).toHaveBeenCalledTimes(1); |
|||
expect(service.request).toHaveBeenCalledWith( |
|||
{ |
|||
method: 'GET', |
|||
url: 'url', |
|||
params: { |
|||
filter: 'x', |
|||
}, |
|||
}, |
|||
{ apiName: 'Default' }, |
|||
); |
|||
}); |
|||
|
|||
it('should return options based on given lookup data', async () => { |
|||
const data = createData([ |
|||
{ |
|||
text: 'foo', |
|||
id: 'bar', |
|||
}, |
|||
{ |
|||
text: 'baz', |
|||
id: 'qux', |
|||
}, |
|||
]); |
|||
|
|||
const options = await createTypeaheadOptions(lookup)(data, 'x').toPromise(); |
|||
expect(options).toEqual([ |
|||
{ |
|||
key: 'foo', |
|||
value: 'bar', |
|||
}, |
|||
{ |
|||
key: 'baz', |
|||
value: 'qux', |
|||
}, |
|||
]); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
function createData(list: { text: string; id: string }[]): any { |
|||
const service = { request: jest.fn(() => of({ list })) }; |
|||
|
|||
return { |
|||
getInjected: () => service, |
|||
index: 0, |
|||
record: null, |
|||
}; |
|||
} |
|||
Loading…
Reference in new issue