master detail view

This commit is contained in:
Jan Prochazka
2020-05-10 09:18:31 +02:00
parent 4e0d8d403c
commit c6695bba32
4 changed files with 75 additions and 91 deletions

View File

@@ -33,7 +33,7 @@ function interpretEscapes(str) {
}); });
} }
const binaryCondition = operator => value => ({ const binaryCondition = (operator) => (value) => ({
conditionType: 'binary', conditionType: 'binary',
operator, operator,
left: { left: {
@@ -45,7 +45,7 @@ const binaryCondition = operator => value => ({
}, },
}); });
const likeCondition = (conditionType, likeString) => value => ({ const likeCondition = (conditionType, likeString) => (value) => ({
conditionType, conditionType,
left: { left: {
exprType: 'placeholder', exprType: 'placeholder',
@@ -56,7 +56,7 @@ const likeCondition = (conditionType, likeString) => value => ({
}, },
}); });
const compoudCondition = conditionType => conditions => { const compoudCondition = (conditionType) => (conditions) => {
if (conditions.length == 1) return conditions[0]; if (conditions.length == 1) return conditions[0];
return { return {
conditionType, conditionType,
@@ -64,7 +64,7 @@ const compoudCondition = conditionType => conditions => {
}; };
}; };
const unaryCondition = conditionType => () => { const unaryCondition = (conditionType) => () => {
return { return {
conditionType, conditionType,
expr: { expr: {
@@ -73,7 +73,7 @@ const unaryCondition = conditionType => () => {
}; };
}; };
const binaryFixedValueCondition = value => () => { const binaryFixedValueCondition = (value) => () => {
return { return {
conditionType: 'binary', conditionType: 'binary',
operator: '=', operator: '=',
@@ -87,7 +87,7 @@ const binaryFixedValueCondition = value => () => {
}; };
}; };
const negateCondition = condition => { const negateCondition = (condition) => {
return { return {
conditionType: 'not', conditionType: 'not',
condition, condition,
@@ -106,6 +106,16 @@ const createParser = (filterType: FilterType) => {
.map(interpretEscapes) .map(interpretEscapes)
.desc('string quoted'), .desc('string quoted'),
string1Num: () =>
token(P.regexp(/"-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?"/, 1))
.map(Number)
.desc('numer quoted'),
string2Num: () =>
token(P.regexp(/'-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?'/, 1))
.map(Number)
.desc('numer quoted'),
number: () => number: () =>
token(P.regexp(/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/)) token(P.regexp(/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/))
.map(Number) .map(Number)
@@ -113,78 +123,39 @@ const createParser = (filterType: FilterType) => {
noQuotedString: () => P.regexp(/[^\s^,^'^"]+/).desc('string unquoted'), noQuotedString: () => P.regexp(/[^\s^,^'^"]+/).desc('string unquoted'),
value: r => P.alt(...allowedValues.map(x => r[x])), value: (r) => P.alt(...allowedValues.map((x) => r[x])),
valueTestEq: r => r.value.map(binaryCondition('=')), valueTestEq: (r) => r.value.map(binaryCondition('=')),
valueTestStr: r => r.value.map(likeCondition('like', '%#VALUE#%')), valueTestStr: (r) => r.value.map(likeCondition('like', '%#VALUE#%')),
comma: () => word(','), comma: () => word(','),
not: () => word('NOT'), not: () => word('NOT'),
notNull: r => r.not.then(r.null).map(unaryCondition('isNotNull')), notNull: (r) => r.not.then(r.null).map(unaryCondition('isNotNull')),
null: () => word('NULL').map(unaryCondition('isNull')), null: () => word('NULL').map(unaryCondition('isNull')),
empty: () => word('EMPTY').map(unaryCondition('isEmpty')), empty: () => word('EMPTY').map(unaryCondition('isEmpty')),
notEmpty: r => r.not.then(r.empty).map(unaryCondition('isNotEmpty')), notEmpty: (r) => r.not.then(r.empty).map(unaryCondition('isNotEmpty')),
true: () => word('TRUE').map(binaryFixedValueCondition(1)), true: () => word('TRUE').map(binaryFixedValueCondition(1)),
false: () => word('FALSE').map(binaryFixedValueCondition(0)), false: () => word('FALSE').map(binaryFixedValueCondition(0)),
eq: r => eq: (r) => word('=').then(r.value).map(binaryCondition('=')),
word('=') ne: (r) => word('!=').then(r.value).map(binaryCondition('<>')),
.then(r.value) lt: (r) => word('<').then(r.value).map(binaryCondition('<')),
.map(binaryCondition('=')), gt: (r) => word('>').then(r.value).map(binaryCondition('>')),
ne: r => le: (r) => word('<=').then(r.value).map(binaryCondition('<=')),
word('!=') ge: (r) => word('>=').then(r.value).map(binaryCondition('>=')),
.then(r.value) startsWith: (r) => word('^').then(r.value).map(likeCondition('like', '#VALUE#%')),
.map(binaryCondition('<>')), endsWith: (r) => word('$').then(r.value).map(likeCondition('like', '%#VALUE#')),
lt: r => contains: (r) => word('+').then(r.value).map(likeCondition('like', '%#VALUE#%')),
word('<') startsWithNot: (r) => word('!^').then(r.value).map(likeCondition('like', '#VALUE#%')).map(negateCondition),
.then(r.value) endsWithNot: (r) => word('!$').then(r.value).map(likeCondition('like', '%#VALUE#')).map(negateCondition),
.map(binaryCondition('<')), containsNot: (r) => word('~').then(r.value).map(likeCondition('like', '%#VALUE#%')).map(negateCondition),
gt: r =>
word('>')
.then(r.value)
.map(binaryCondition('>')),
le: r =>
word('<=')
.then(r.value)
.map(binaryCondition('<=')),
ge: r =>
word('>=')
.then(r.value)
.map(binaryCondition('>=')),
startsWith: r =>
word('^')
.then(r.value)
.map(likeCondition('like', '#VALUE#%')),
endsWith: r =>
word('$')
.then(r.value)
.map(likeCondition('like', '%#VALUE#')),
contains: r =>
word('+')
.then(r.value)
.map(likeCondition('like', '%#VALUE#%')),
startsWithNot: r =>
word('!^')
.then(r.value)
.map(likeCondition('like', '#VALUE#%'))
.map(negateCondition),
endsWithNot: r =>
word('!$')
.then(r.value)
.map(likeCondition('like', '%#VALUE#'))
.map(negateCondition),
containsNot: r =>
word('~')
.then(r.value)
.map(likeCondition('like', '%#VALUE#%'))
.map(negateCondition),
element: r => P.alt(...allowedElements.map(x => r[x])).trim(whitespace), element: (r) => P.alt(...allowedElements.map((x) => r[x])).trim(whitespace),
factor: r => r.element.sepBy(whitespace).map(compoudCondition('and')), factor: (r) => r.element.sepBy(whitespace).map(compoudCondition('and')),
list: r => r.factor.sepBy(r.comma).map(compoudCondition('or')), list: (r) => r.factor.sepBy(r.comma).map(compoudCondition('or')),
}; };
const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString']; const allowedValues = []; // 'string1', 'string2', 'number', 'noQuotedString'];
if (filterType == 'string') allowedValues.push('string1', 'string2', 'noQuotedString'); if (filterType == 'string') allowedValues.push('string1', 'string2', 'noQuotedString');
if (filterType == 'number') allowedValues.push('number'); if (filterType == 'number') allowedValues.push('string1Num', 'string2Num', 'number');
const allowedElements = ['null', 'notNull', 'eq', 'ne']; const allowedElements = ['null', 'notNull', 'eq', 'ne'];
if (filterType == 'number' || filterType == 'datetime') allowedElements.push('lt', 'gt', 'le', 'ge'); if (filterType == 'number' || filterType == 'datetime') allowedElements.push('lt', 'gt', 'le', 'ge');

View File

@@ -426,8 +426,10 @@ export default function DataGridCore(props) {
}, [jslid]); }, [jslid]);
React.useEffect(() => { React.useEffect(() => {
if (props.onSelectedRowsChanged) props.onSelectedRowsChanged(getSelectedRowData()) if (props.onRefSourceRowsChanged) {
}, [selectedCells]); props.onRefSourceRowsChanged(getSelectedRowData());
}
}, [selectedCells, props.refReloadToken]);
// const handleCloseInplaceEditor = React.useCallback( // const handleCloseInplaceEditor = React.useCallback(
// mode => { // mode => {

View File

@@ -27,10 +27,15 @@ export default function TableDataGrid({
const [childConfig, setChildConfig] = React.useState(createGridConfig()); const [childConfig, setChildConfig] = React.useState(createGridConfig());
const [myCache, setMyCache] = React.useState(createGridCache()); const [myCache, setMyCache] = React.useState(createGridCache());
const [childCache, setChildCache] = React.useState(createGridCache()); const [childCache, setChildCache] = React.useState(createGridCache());
const [refReloadToken, setRefReloadToken] = React.useState(0);
const connection = useConnectionInfo({ conid }); const connection = useConnectionInfo({ conid });
const [reference, setReference] = React.useState(null); const [reference, setReference] = React.useState(null);
React.useEffect(() => {
setRefReloadToken((v) => v + 1);
}, [reference]);
const display = React.useMemo( const display = React.useMemo(
() => () =>
connection connection
@@ -64,27 +69,31 @@ export default function TableDataGrid({
} }
}, [conid, database, display]); }, [conid, database, display]);
const handleSelectedRowsChanged = (selectedRows) => { const handleRefSourcedRowsChanged = React.useCallback(
const filters = { (selectedRows) => {
...(config || myConfig).filters, if (!reference) return;
..._.fromPairs( const filters = {
reference.columns.map((col) => [ ...(config || myConfig).filters,
col.refName, ..._.fromPairs(
selectedRows.map((x) => getFilterValueExpression(x[col.baseName])).join(','), reference.columns.map((col) => [
]) col.refName,
), selectedRows.map((x) => getFilterValueExpression(x[col.baseName])).join(','),
}; ])
if (stableStringify(filters) != stableStringify((config || myConfig).filters)) { ),
setChildConfig((cfg) => ({ };
...cfg, if (stableStringify(filters) != stableStringify((config || childConfig).filters)) {
filters, setChildConfig((cfg) => ({
})); ...cfg,
setChildCache((ca) => ({ filters,
...ca, }));
refreshTime: new Date().getTime(), setChildCache((ca) => ({
})); ...ca,
} refreshTime: new Date().getTime(),
}; }));
}
},
[config || childConfig, reference]
);
if (!display) return null; if (!display) return null;
@@ -101,7 +110,8 @@ export default function TableDataGrid({
toolbarPortalRef={toolbarPortalRef} toolbarPortalRef={toolbarPortalRef}
showReferences showReferences
onReferenceClick={setReference} onReferenceClick={setReference}
onSelectedRowsChanged={reference ? handleSelectedRowsChanged : null} onRefSourceRowsChanged={reference ? handleRefSourcedRowsChanged : null}
refReloadToken={refReloadToken.toString()}
/> />
{reference && ( {reference && (
<TableDataGrid <TableDataGrid

View File

@@ -11,5 +11,6 @@ export interface DataGridProps {
jslid?: string; jslid?: string;
showReferences?: boolean; showReferences?: boolean;
onReferenceClick?: (def: GridReferenceDefinition) => void; onReferenceClick?: (def: GridReferenceDefinition) => void;
onSelectedRowsChanged?: Function; onRefSourceRowsChanged?: Function;
refReloadToken?: string;
} }