Skip to content

Commit

Permalink
Merge pull request #756 from complexdatacollective/feature/skip-logic…
Browse files Browse the repository at this point in the history
…-categorical-counts

add categorical count options to skip logic
  • Loading branch information
jthrilly authored Mar 16, 2022
2 parents a069351 + 69db3d5 commit 76079f9
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 15 deletions.
2 changes: 1 addition & 1 deletion network-canvas
24 changes: 22 additions & 2 deletions src/components/Query/Rules/EditEgoRule.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
import { compose } from 'recompose';
import { isArray, isNil } from 'lodash';
import DetachedField from '@components/DetachedField';
import NativeSelect from '@components/Form/Fields/NativeSelect';
import { operatorsWithValue } from './options';
import { operatorsWithValue, operatorsWithOptionCount } from './options';
import EditValue from './EditValue';
import withRuleChangeHandler from './withRuleChangeHandler';
import withOptions from './withOptions';
Expand All @@ -27,7 +28,12 @@ const EditEgoRule = ({
const options = rule && rule.options;
const optionsWithDefaults = { ...defaultOptions, ...options };
const operatorNeedsValue = operatorsWithValue.has(optionsWithDefaults.operator);

const operatorNeedsOptionCount = operatorsWithOptionCount.has(optionsWithDefaults.operator);
const countFriendlyValue = !isNil(optionsWithDefaults.value) ? optionsWithDefaults.value : '';
const optionsWithCounts = {
...optionsWithDefaults,
value: isArray(optionsWithDefaults.value) ? '' : countFriendlyValue,
};
return (
<>
<Section
Expand Down Expand Up @@ -72,6 +78,20 @@ const EditEgoRule = ({
/>
</Section>
)}
{ operatorNeedsOptionCount
&& (
<Section
title="Selected Option Count"
>
<EditValue
variableType="number"
placeholder="Enter a value..."
onChange={handleRuleChange}
value={optionsWithCounts.value}
validation={{ requiredAcceptsZero: true }}
/>
</Section>
)}
</>
);
};
Expand Down
23 changes: 22 additions & 1 deletion src/components/Query/Rules/EditEntityRule.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import { compose } from 'recompose';
import { isArray, isNil } from 'lodash';
import DetachedField from '@components/DetachedField';
import NativeSelect from '@components/Form/Fields/NativeSelect';
import RadioGroup from '@codaco/ui/lib/components/Fields/RadioGroup';
import EditValue from './EditValue';
import Section from '../../EditorLayout/Section';
import { operatorsWithValue } from './options';
import { operatorsWithValue, operatorsWithOptionCount } from './options';
import withRuleChangeHandler from './withRuleChangeHandler';
import withOptions from './withOptions';
import {
Expand Down Expand Up @@ -39,6 +40,12 @@ const EditEntityRule = ({
const operatorNeedsValue = operatorsWithValue.has(optionsWithDefaults.operator);
const isVariableRule = entityRuleType === entityRuleTypes.VARIABLE_RULE;
const isTypeRule = entityRuleType === entityRuleTypes.TYPE_RULE;
const operatorNeedsOptionCount = operatorsWithOptionCount.has(optionsWithDefaults.operator);
const countFriendlyValue = !isNil(optionsWithDefaults.value) ? optionsWithDefaults.value : '';
const optionsWithCounts = {
...optionsWithDefaults,
value: isArray(optionsWithDefaults.value) ? '' : countFriendlyValue,
};

return (
<>
Expand Down Expand Up @@ -145,6 +152,20 @@ const EditEntityRule = ({
/>
</Section>
)}
{ isVariableRule && operatorNeedsOptionCount
&& (
<Section
title="Selected Option Count"
>
<EditValue
variableType="number"
placeholder="Enter a value..."
onChange={handleRuleChange}
value={optionsWithCounts.value}
validation={{ requiredAcceptsZero: true }}
/>
</Section>
)}
</>
);
};
Expand Down
18 changes: 17 additions & 1 deletion src/components/Query/Rules/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export const operators = {
GREATER_THAN_OR_EQUAL: 'GREATER_THAN_OR_EQUAL',
LESS_THAN: 'LESS_THAN',
LESS_THAN_OR_EQUAL: 'LESS_THAN_OR_EQUAL',
OPTIONS_GREATER_THAN: 'OPTIONS_GREATER_THAN',
OPTIONS_LESS_THAN: 'OPTIONS_LESS_THAN',
OPTIONS_EQUALS: 'OPTIONS_EQUALS',
OPTIONS_NOT_EQUALS: 'OPTIONS_NOT_EQUALS',
};

// List of operator options with labels
Expand All @@ -33,6 +37,10 @@ export const operatorsAsOptions = [
[operators.LESS_THAN_OR_EQUAL, 'is less than or exactly'],
[operators.INCLUDES, 'includes'],
[operators.EXCLUDES, 'excludes'],
[operators.OPTIONS_GREATER_THAN, 'number of selected options is greater than'],
[operators.OPTIONS_LESS_THAN, 'number of selected options is less than'],
[operators.OPTIONS_EQUALS, 'number of selected options is exactly'],
[operators.OPTIONS_NOT_EQUALS, 'number of selected options is not'],
].map(([value, label]) => ({ value, label }));

// Operators that also require a value to be used
Expand All @@ -47,12 +55,20 @@ export const operatorsWithValue = new Set([
operators.EXCLUDES,
]);

// Operators that also require a count of options
export const operatorsWithOptionCount = new Set([
operators.OPTIONS_GREATER_THAN,
operators.OPTIONS_LESS_THAN,
operators.OPTIONS_EQUALS,
operators.OPTIONS_NOT_EQUALS,
]);

export const operatorsByType = {
text: new Set(['EXACTLY', 'NOT']),
number: new Set(['EXACTLY', 'NOT', 'GREATER_THAN', 'GREATER_THAN_OR_EQUAL', 'LESS_THAN', 'LESS_THAN_OR_EQUAL']),
boolean: new Set(['EXACTLY', 'NOT']),
ordinal: new Set(['EXACTLY', 'NOT']),
categorical: new Set(['INCLUDES', 'EXCLUDES']),
categorical: new Set(['INCLUDES', 'EXCLUDES', 'OPTIONS_GREATER_THAN', 'OPTIONS_LESS_THAN', 'OPTIONS_EQUALS', 'OPTIONS_NOT_EQUALS']),
exists: new Set(['EXISTS', 'NOT_EXISTS']), // TODO: Better words for these?
};

Expand Down
24 changes: 18 additions & 6 deletions src/components/Query/Rules/validateRule.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { isEmpty, isNil } from 'lodash';
import { operatorsWithValue } from './options';
import { isArray, isEmpty, isNil } from 'lodash';
import { operatorsWithValue, operatorsWithOptionCount } from './options';

const valididateField = (value) => {
const validateField = (value) => {
if (isArray(value)) {
return value.length > 0;
}
const type = typeof value;
switch (type) {
case 'string':
Expand All @@ -18,7 +21,7 @@ const valididateField = (value) => {
};

const validateFields = (fields = [], options = {}) => (
fields.every((field) => valididateField(options[field]))
fields.every((field) => validateField(options[field]))
);

const validateRule = (rule) => {
Expand All @@ -27,20 +30,29 @@ const validateRule = (rule) => {
switch (rule.type) {
case 'alter': {
if (Object.prototype.hasOwnProperty.call(options, 'attribute')) {
if (operatorsWithValue.has(options.operator)) {
if (operatorsWithValue.has(options.operator)
|| operatorsWithOptionCount.has(options.operator)) {
return validateFields(['type', 'attribute', 'operator', 'value'], options);
}
return validateFields(['type', 'attribute', 'operator'], options);
}
return validateFields(['type', 'operator'], options);
}
case 'ego': {
if (operatorsWithValue.has(options.operator)) {
if (operatorsWithValue.has(options.operator)
|| operatorsWithOptionCount.has(options.operator)) {
return validateFields(['attribute', 'operator', 'value'], options);
}
return validateFields(['attribute', 'operator'], options);
}
case 'edge':
if (Object.prototype.hasOwnProperty.call(options, 'attribute')) {
if (operatorsWithValue.has(options.operator)
|| operatorsWithOptionCount.has(options.operator)) {
return validateFields(['type', 'attribute', 'operator', 'value'], options);
}
return validateFields(['type', 'attribute', 'operator'], options);
}
return validateFields(['type', 'operator'], options);
default:
return false;
Expand Down
17 changes: 15 additions & 2 deletions src/components/Query/Rules/withRuleChangeHandler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { withHandlers } from 'recompose';
import { keys, pick } from 'lodash';
import {
isArray,
isNil,
keys,
pick,
} from 'lodash';
import { makeGetOptionsWithDefaults } from './defaultRule';
import { operatorsWithOptionCount } from './options';

const RULE_ORDER = [
'type',
Expand All @@ -26,9 +32,16 @@ const withRuleChangeHandlers = withHandlers({
// ensure reset values have defaults
const optionsWithDefaults = getOptionsWithDefaults(options);

const operatorNeedsOptionCount = operatorsWithOptionCount.has(optionsWithDefaults.operator)
&& isArray(optionsWithDefaults.value);
const countFriendlyValue = !isNil(optionsWithDefaults.value) ? optionsWithDefaults.value : '';

onChange({
...rule,
options: optionsWithDefaults,
options: {
...optionsWithDefaults,
value: operatorNeedsOptionCount ? '' : countFriendlyValue,
},
});
};
},
Expand Down
2 changes: 1 addition & 1 deletion src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const COLOR_PALETTE_BY_ENTITY = {
};

// Target protocol schema version. Used to determine compatibility & migration
export const APP_SCHEMA_VERSION = 6;
export const APP_SCHEMA_VERSION = 7;

// Maps for supported asset types within the app. Used by asset chooser.
export const SUPPORTED_EXTENSION_TYPE_MAP = {
Expand Down

0 comments on commit 76079f9

Please sign in to comment.