UNPKG

@adaptabletools/adaptable

Version:

Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

605 lines (604 loc) 24.8 kB
import { isAfter } from 'date-fns'; import { isBefore } from 'date-fns'; import { isEqual } from 'date-fns'; import { isFuture } from 'date-fns'; import { isPast } from 'date-fns'; import { isSameDay } from 'date-fns'; import { isThisMonth } from 'date-fns'; import { isThisQuarter } from 'date-fns'; import { isThisWeek } from 'date-fns'; import { isThisYear } from 'date-fns'; import { isToday } from 'date-fns'; import { isTomorrow } from 'date-fns'; import { isYesterday } from 'date-fns'; import StringExtensions from '../../Utilities/Extensions/StringExtensions'; import { parseDateValue } from '../../Utilities/Helpers/DateHelper'; import Helper from '../../Utilities/Helpers/Helper'; /** * Array of Predicate Defs which are shipped by AdapTable */ export const SystemPredicateDefs = [ { id: 'In', label: 'In', icon: { text: 'IN' }, columnScope: { DataTypes: ['text', 'number', 'date'] }, moduleScope: ['columnFilter', 'flashingcell', 'formatColumn', 'alert', 'badgeStyle'], handler: (context) => { const { inputs = [], column, value, adaptableApi } = context; const predicateInputs = (context.inputs || []).reduce((acc, input) => { const predicate = adaptableApi.predicateApi.getPredicateDefById(input); if (predicate) { acc.push(predicate); } return acc; }, []); if (predicateInputs.length) { const nestedContext = { ...context }; delete nestedContext.inputs; const predicateResult = predicateInputs.some((predicate) => { return adaptableApi.predicateApi.handlePredicate({ PredicateId: predicate.id, }, nestedContext, false); }); if (predicateResult) { // We want to use the only true values, to allow for multiple predicates to be used return predicateResult; } } if (inputs.length === 0) { return true; } if (column.dataType === 'date') { return inputs.some((input) => { if (adaptableApi.optionsApi.getPredicateOptions().evaluateValuesPredicateUsingTime) { return isEqual(input, value); } else { return isSameDay(parseDateValue(input), parseDateValue(value)); } }); } if (column.dataType === 'number') { return inputs.includes(value); } if (column.dataType === 'text') { return adaptableApi.predicateApi.useCaseSensitivity() ? inputs .map((i) => { return i?.toLocaleLowerCase(); }) .includes(value?.toLocaleLowerCase()) : inputs.includes(value); } return true; }, toString: ({ inputs }) => `IN (${inputs.join(', ')})`, shortcuts: ['#', '['], }, { id: 'NotIn', label: 'Not In', icon: { text: '!IN' }, columnScope: { DataTypes: ['text', 'number', 'date'] }, moduleScope: ['columnFilter', 'flashingcell', 'formatColumn', 'alert', 'badgeStyle'], handler: (context) => { const { inputs, column, value, adaptableApi } = context; const predicateInputs = context.inputs.reduce((acc, input) => { const predicate = adaptableApi.predicateApi.getPredicateDefById(input); if (predicate) { acc.push(predicate); } return acc; }, []); if (predicateInputs.length) { const nestedContext = { ...context }; delete nestedContext.inputs; const predicateResult = predicateInputs.every((predicate) => { const res = adaptableApi.predicateApi.handlePredicate({ PredicateId: predicate.id, }, nestedContext, false); return res === false; }); if (!predicateResult) { // We want to use the only true values, to allow for multiple predicates to be used return false; } } // basically negation of IN if (inputs.length === 0) { return true; } if (column.dataType === 'date') { if (adaptableApi.optionsApi.getPredicateOptions().evaluateValuesPredicateUsingTime) { return inputs.every((input) => { return !isEqual(input, value); }); } else { return inputs.every((input) => { return !isSameDay(parseDateValue(input), parseDateValue(value)); }); } } if (column.dataType === 'number') { return !inputs.includes(value); } if (column.dataType === 'text') { return adaptableApi.predicateApi.useCaseSensitivity() ? !inputs .map((i) => { return i?.toLocaleLowerCase(); }) .includes(value?.toLocaleLowerCase()) : !inputs.includes(value); } return true; }, toString: ({ inputs }) => `Exclude (${inputs.join(', ')})`, }, { id: 'Blanks', label: 'Blanks', icon: { name: 'unfilled-circle' }, columnScope: { All: true }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], handler: ({ value }) => Helper.isInputNullOrEmpty(value), }, { id: 'NonBlanks', label: 'Non Blanks', icon: { name: 'filled-circle' }, columnScope: { All: true }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], handler: ({ value }) => Helper.isInputNotNullOrEmpty(value), }, // Numeric System Filters { id: 'GreaterThan', label: 'Greater Than', icon: { name: 'greater-than' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'number' }], handler: ({ value, inputs }) => Number(value) > Number(inputs[0]), toString: ({ inputs }) => `> ${inputs[0] ?? ''}`, shortcuts: ['>'], }, { id: 'LessThan', label: 'Less Than', icon: { name: 'less-than' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'number' }], handler: ({ value, inputs }) => Number(value) < Number(inputs[0]), toString: ({ inputs }) => `< ${inputs[0] ?? ''}`, shortcuts: ['<'], }, { id: 'Positive', label: 'Positive', icon: { text: '>0' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], handler: ({ value }) => Number(value) > 0, }, { id: 'Negative', label: 'Negative', icon: { text: '<0' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], handler: ({ value }) => Number(value) < 0, }, { id: 'Zero', label: 'Zero', icon: { text: '=0' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], handler: ({ value }) => { if (typeof value === 'string' && !StringExtensions.IsNumeric(value)) { return false; } if (Helper.objectNotExists(value)) { return false; } return Number(value) === 0; }, }, { id: 'Equals', label: 'Equals', icon: { name: 'equals' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'number' }], handler: ({ value, inputs }) => { const input = inputs[0]; if ((typeof value === 'string' && !StringExtensions.IsNumeric(value)) || (typeof input === 'string' && !StringExtensions.IsNumeric(input))) { return false; } return Number(value) === Number(inputs[0]); }, toString: ({ inputs }) => `= ${inputs[0] ?? ''}`, shortcuts: ['='], }, { id: 'NotEquals', label: 'Not Equals', icon: { name: 'not-equal' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'number' }], handler: ({ value, inputs }) => { const input = inputs[0]; if ((typeof value === 'string' && !StringExtensions.IsNumeric(value)) || (typeof input === 'string' && !StringExtensions.IsNumeric(input))) { return false; } return Number(value) !== Number(inputs[0]); }, toString: ({ inputs }) => `!= ${inputs[0] ?? ''}`, shortcuts: ['!='], }, { id: 'Between', label: 'Between', icon: { text: 'BE' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'number' }, { type: 'number' }], handler: ({ value, inputs }) => Number(value) >= Number(inputs[0]) && Number(value) <= Number(inputs[1]), toString: ({ inputs }) => `Between ${inputs[0] ?? ''}:${inputs[1]}`, shortcuts: [':'], }, { id: 'NotBetween', label: 'Not Between', icon: { text: '!BE' }, columnScope: { DataTypes: ['number'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'number' }, { type: 'number' }], handler: ({ value, inputs }) => Number(value) < Number(inputs[0]) || Number(value) > Number(inputs[1]), toString: ({ inputs }) => `Not Between ${inputs[0] ?? ''}:${inputs[1]}`, shortcuts: ['!:'], }, // String System Filters { id: 'Is', label: 'Equals', icon: { name: 'equals' }, columnScope: { DataTypes: ['text'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'text' }], handler: ({ value, inputs, adaptableApi }) => { if (!value) { return false; } const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity(); const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value); const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]); return v == i; }, toString: ({ inputs }) => `= ${inputs[0] ?? ''}`, shortcuts: ['='], }, { id: 'IsNot', label: 'Not Equals', icon: { name: 'not-equal' }, columnScope: { DataTypes: ['text'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'text' }], handler: ({ value, inputs, adaptableApi }) => { if (!value) { return true; } const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity(); const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value); const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]); return v != i; }, toString: ({ inputs }) => `!= ${inputs[0] ?? ''}`, shortcuts: ['!='], }, { id: 'Contains', label: 'Contains', icon: { name: 'contains' }, columnScope: { DataTypes: ['text'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'text' }], handler: ({ value, inputs, adaptableApi }) => { if (!value) { return false; } const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity(); const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value); const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]); return v.indexOf(i) !== -1; }, toString: ({ inputs }) => `Contains ${inputs[0] ?? ''}`, }, { id: 'NotContains', label: 'Not Contains', icon: { name: 'not-contains' }, columnScope: { DataTypes: ['text'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'text' }], handler: ({ value, inputs, adaptableApi }) => { if (!value) { return true; } const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity(); const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value); const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]); return v.indexOf(i) === -1; }, toString: ({ inputs }) => `Not Contains ${inputs[0] ?? ''}`, }, { id: 'StartsWith', label: 'Starts With', icon: { name: 'starts-with' }, columnScope: { DataTypes: ['text'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'text' }], handler: ({ value, inputs, adaptableApi }) => { if (!value) { return false; } const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity(); const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value); const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]); return v.startsWith(i); }, toString: ({ inputs }) => `Starts With ${inputs[0] ?? ''}`, }, { id: 'EndsWith', label: 'Ends With', icon: { name: 'ends-with' }, columnScope: { DataTypes: ['text'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'text' }], handler: ({ value, inputs, adaptableApi }) => { if (!value) { return false; } const ignoreCase = !adaptableApi.predicateApi.useCaseSensitivity(); const v = ignoreCase ? String(value).toLocaleLowerCase() : String(value); const i = ignoreCase ? String(inputs[0]).toLocaleLowerCase() : String(inputs[0]); return v.endsWith(i); }, toString: ({ inputs }) => `Ends With ${inputs[0] ?? ''}`, }, { id: 'Regex', label: 'Regex', icon: { name: 'regex' }, columnScope: { DataTypes: ['text'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn', 'badgeStyle'], inputs: [{ type: 'text' }], handler: ({ value, inputs }) => new RegExp(inputs[0]).test(value), toString: ({ inputs }) => `Regex ${inputs[0] ?? ''}`, }, // Date System Filters { id: 'Today', label: 'Today', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isToday(parseDateValue(value)), }, { id: 'Yesterday', label: 'Yesterday', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isYesterday(parseDateValue(value)), }, { id: 'Tomorrow', label: 'Tomorrow', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isTomorrow(parseDateValue(value)), }, { id: 'ThisWeek', label: 'This Week', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isThisWeek(parseDateValue(value)), }, { id: 'ThisMonth', label: 'This Month', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isThisMonth(parseDateValue(value)), }, { id: 'ThisQuarter', label: 'This Quarter', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isThisQuarter(parseDateValue(value)), }, { id: 'ThisYear', label: 'This Year', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isThisYear(parseDateValue(value)), }, { id: 'InPast', label: 'In Past', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isPast(parseDateValue(value)), }, { id: 'InFuture', label: 'In Future', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => isFuture(parseDateValue(value)), }, { id: 'After', label: 'After', icon: { name: 'greater-than' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], inputs: [{ type: 'date' }], handler: ({ value, inputs }) => isAfter(parseDateValue(value), parseDateValue(inputs[0])), toString: ({ inputs }) => `> ${inputs[0] ?? ''}`, }, { id: 'Before', label: 'Before', icon: { name: 'less-than' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], inputs: [{ type: 'date' }], handler: ({ value, inputs }) => isBefore(parseDateValue(value), parseDateValue(inputs[0])), toString: ({ inputs }) => `< ${inputs[0] ?? ''}`, }, { id: 'On', label: 'Equals', icon: { name: 'equals' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], inputs: [{ type: 'date' }], handler: ({ value, inputs }) => isSameDay(parseDateValue(value), parseDateValue(inputs[0])), toString: ({ inputs }) => `= ${inputs[0] ?? ''}`, }, { id: 'NotOn', label: 'NotEquals', icon: { name: 'not-equal' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], inputs: [{ type: 'date' }], handler: ({ value, inputs }) => !isSameDay(parseDateValue(value), parseDateValue(inputs[0])), toString: ({ inputs }) => `!= ${inputs[0] ?? ''}`, }, { id: 'NextWorkDay', label: 'Next Work Day', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value, adaptableApi }) => isSameDay(parseDateValue(value), adaptableApi.calendarApi.getNextWorkingDay()), }, { id: 'LastWorkDay', label: 'Last Work Day', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value, adaptableApi }) => isSameDay(parseDateValue(value), adaptableApi.calendarApi.getPreviousWorkingDay()), }, { id: 'WorkDay', label: 'Working Day', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value, adaptableApi }) => adaptableApi.calendarApi.isWorkingDay(value), }, { id: 'Holiday', label: 'Holiday', icon: { name: 'calendar' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value, adaptableApi }) => adaptableApi.calendarApi.isHoliday(value), }, { id: 'InRange', label: 'Range', icon: { name: 'date-range' }, columnScope: { DataTypes: ['date'] }, moduleScope: ['columnFilter'], inputs: [{ type: 'date' }, { type: 'date' }], handler: ({ value, inputs }) => new Date(value) >= new Date(inputs[0]) && new Date(value) <= new Date(inputs[1]), }, // Boolean System Filters { id: 'True', label: 'True', icon: { text: 'T' }, columnScope: { DataTypes: ['boolean'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => Boolean(value) === true, }, { id: 'False', label: 'False', icon: { text: 'F' }, columnScope: { DataTypes: ['boolean'] }, moduleScope: ['columnFilter', 'alert', 'flashingcell', 'formatColumn'], handler: ({ value }) => Boolean(value) === false, }, { id: 'BooleanToggle', label: 'BooleanToggle', icon: { name: 'boolean-list' }, columnScope: { DataTypes: ['boolean'] }, moduleScope: ['columnFilter'], inputs: [{ type: 'boolean' }], // working with string aliases instead of booleans because the ColumnFilterAPI cannot handle falsy filter values (it ignores them) handler: ({ value, inputs }) => { if (inputs[0] == 'all') { // if it's indeterminate, all values (true&false) are matched return true; } const booleanInputValue = inputs[0] === 'checked' ? true : false; return Boolean(value) === Boolean(booleanInputValue); }, }, // Other System Filters { id: 'AnyChange', label: 'Any Change', columnScope: { All: true }, moduleScope: ['alert', 'flashingcell'], handler: ({ value, oldValue }) => value !== oldValue, }, { id: 'PercentChange', label: 'Percent Change', columnScope: { DataTypes: ['number'] }, moduleScope: ['alert', 'flashingcell'], inputs: [{ type: 'number' }], handler: ({ value, oldValue, inputs }) => { const change = Math.abs(Number(value) - Number(oldValue)); const base = Math.min(Number(value), Number(oldValue)); const threshold = Number(inputs[0]); return (change / base) * 100 > threshold; }, }, ]; export const SystemFilterPredicateIds = SystemPredicateDefs.filter((p) => p.moduleScope.includes('columnFilter')).map((p) => p.id); export const SystemAlertPredicateIds = SystemPredicateDefs.filter((p) => p.moduleScope.includes('alert')).map((p) => p.id); export const SystemFormatColumnPredicateIds = SystemPredicateDefs.filter((p) => p.moduleScope.includes('formatColumn')).map((p) => p.id); export const SystemFlashingCellPredicateIds = SystemPredicateDefs.filter((p) => p.moduleScope.includes('flashingcell')).map((p) => p.id); export const SystemBadgeStylePredicateIds = SystemPredicateDefs.filter((p) => p.moduleScope.includes('badgeStyle')).map((p) => p.id);