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',
operator,
left: {
@@ -45,7 +45,7 @@ const binaryCondition = operator => value => ({
},
});
const likeCondition = (conditionType, likeString) => value => ({
const likeCondition = (conditionType, likeString) => (value) => ({
conditionType,
left: {
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];
return {
conditionType,
@@ -64,7 +64,7 @@ const compoudCondition = conditionType => conditions => {
};
};
const unaryCondition = conditionType => () => {
const unaryCondition = (conditionType) => () => {
return {
conditionType,
expr: {
@@ -73,7 +73,7 @@ const unaryCondition = conditionType => () => {
};
};
const binaryFixedValueCondition = value => () => {
const binaryFixedValueCondition = (value) => () => {
return {
conditionType: 'binary',
operator: '=',
@@ -87,7 +87,7 @@ const binaryFixedValueCondition = value => () => {
};
};
const negateCondition = condition => {
const negateCondition = (condition) => {
return {
conditionType: 'not',
condition,
@@ -106,6 +106,16 @@ const createParser = (filterType: FilterType) => {
.map(interpretEscapes)
.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: () =>
token(P.regexp(/-?(0|[1-9][0-9]*)([.][0-9]+)?([eE][+-]?[0-9]+)?/))
.map(Number)
@@ -113,78 +123,39 @@ const createParser = (filterType: FilterType) => {
noQuotedString: () => P.regexp(/[^\s^,^'^"]+/).desc('string unquoted'),
value: r => P.alt(...allowedValues.map(x => r[x])),
valueTestEq: r => r.value.map(binaryCondition('=')),
valueTestStr: r => r.value.map(likeCondition('like', '%#VALUE#%')),
value: (r) => P.alt(...allowedValues.map((x) => r[x])),
valueTestEq: (r) => r.value.map(binaryCondition('=')),
valueTestStr: (r) => r.value.map(likeCondition('like', '%#VALUE#%')),
comma: () => word(','),
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')),
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)),
false: () => word('FALSE').map(binaryFixedValueCondition(0)),
eq: r =>
word('=')
.then(r.value)
.map(binaryCondition('=')),
ne: r =>
word('!=')
.then(r.value)
.map(binaryCondition('<>')),
lt: r =>
word('<')
.then(r.value)
.map(binaryCondition('<')),
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),
eq: (r) => word('=').then(r.value).map(binaryCondition('=')),
ne: (r) => word('!=').then(r.value).map(binaryCondition('<>')),
lt: (r) => word('<').then(r.value).map(binaryCondition('<')),
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),
factor: r => r.element.sepBy(whitespace).map(compoudCondition('and')),
list: r => r.factor.sepBy(r.comma).map(compoudCondition('or')),
element: (r) => P.alt(...allowedElements.map((x) => r[x])).trim(whitespace),
factor: (r) => r.element.sepBy(whitespace).map(compoudCondition('and')),
list: (r) => r.factor.sepBy(r.comma).map(compoudCondition('or')),
};
const allowedValues = []; // 'string1', 'string2', 'number', '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'];
if (filterType == 'number' || filterType == 'datetime') allowedElements.push('lt', 'gt', 'le', 'ge');

View File

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

View File

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

View File

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