Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use AG Grid filter types #12072

Merged
merged 23 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import icons from '@/assets/icons.svg'
import AgGridTableView, { commonContextMenuActions } from '@/components/shared/AgGridTableView.vue'
import {
GridFilterModel,
useTableVizToolbar,
type SortModel,
} from '@/components/visualizations/TableVisualization/tableVizToolbar'
Expand Down Expand Up @@ -123,7 +124,7 @@ const rowCount = ref(0)
const showRowCount = ref(true)
const isTruncated = ref(false)
const isCreateNodeEnabled = ref(false)
const filterModel = ref({})
const filterModel = ref<GridFilterModel[]>([])
const sortModel = ref<SortModel[]>([])
const dataGroupingMap = shallowRef<Map<string, boolean>>()
const defaultColDef: Ref<ColDef> = ref({
Expand Down Expand Up @@ -323,6 +324,20 @@ function getValueTypeIcon(valueType: string) {
}
}

function getFilterType(valueType: string) {
switch (valueType) {
case 'Date':
return 'agDateColumnFilter'
case 'Integer':
case 'Float':
case 'Decimal':
case 'Byte':
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use isNumericType

return 'agNumberColumnFilter'
default:
return 'agSetColumnFilter'
}
}

/**
* Generates the column definition for the table vizulization, including displaying the data value type and
* data quality indicators.
Expand All @@ -341,6 +356,7 @@ function toField(

const displayValue = valueType ? valueType.display_text : null
const icon = valueType ? getValueTypeIcon(valueType.constructor) : null
const filterType = valueType ? getFilterType(valueType.constructor) : null

const dataQualityMetrics =
typeof props.data === 'object' && 'data_quality_metrics' in props.data ?
Expand Down Expand Up @@ -374,6 +390,10 @@ function toField(
return {
field: name,
headerName: name, // AGGrid would demangle it its own way if not specified.
filter: filterType,
filterParams: {
maxNumConditions: 1,
},
headerComponentParams: {
template,
setAriaSort: () => {},
Expand Down Expand Up @@ -698,6 +718,7 @@ const createDateValue = (item: string, module: Ast.MutableModule) => {
const dateOrTimePattern = Pattern.parseExpression('(Date.new __ __ __)')
const dateTimeParts = item
.match(/\d+/g)!
.filter((part, i) => i < 3)
.map((part) => Ast.tryNumberToEnso(Number(part), module)!)
return dateOrTimePattern.instantiateCopied([...dateTimeParts])
}
Expand All @@ -710,7 +731,7 @@ function checkSortAndFilter(e: SortChangedEvent) {
return
}
const colState = gridApi.getColumnState()
const filter = gridApi.getFilterModel()
const gridFilterModel = gridApi.getFilterModel()
const sort = colState
.map((cs) => {
if (cs.sort) {
Expand All @@ -722,14 +743,26 @@ function checkSortAndFilter(e: SortChangedEvent) {
}
})
.filter((sort) => sort)
if (sort.length || Object.keys(filter).length) {
const filter = Object.entries(gridFilterModel).map(([key, value]) => {
return {
columnName: key,
filterType: value.filterType,
filterAction: value.type,
filter: value.filter,
filterTo: value.filterTo,
dateFrom: value.dateFrom,
dateTo: value.dateTo,
values: value.values,
}
})
if (sort.length || filter.length) {
isCreateNodeEnabled.value = true
sortModel.value = sort as SortModel[]
filterModel.value = filter
} else {
isCreateNodeEnabled.value = false
sortModel.value = []
filterModel.value = {}
filterModel.value = []
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,48 @@ export type SortModel = {
sortDirection: SortDirection
sortIndex: number
}
type FilterType = 'number' | 'date' | 'set'
type FilterAction =
| 'equals'
| 'notEqual'
| 'greaterThan'
| 'greaterThanOrEqual'
| 'lessThan'
| 'lessThanOrEqual'
| 'inRange'
| 'blank'
| 'notBlank'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type FilterAction =
| 'equals'
| 'notEqual'
| 'greaterThan'
| 'greaterThanOrEqual'
| 'lessThan'
| 'lessThanOrEqual'
| 'inRange'
| 'blank'
| 'notBlank'
type FilterAction = keyof typeof ActionMap

export type GridFilterModel = {
columnName: string
filterType: FilterType
filter?: string
filterTo?: string
dateFrom?: string
dateTo?: string
values?: string[]
filterAction?: FilterAction
}
type FilterValueRange = {
toValue: string
fromValue: string
}
//The filter value can be a single value for comparisons such as 'equals' or 'greater than,' a list for 'is in' filtering, or two values that define a range.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a doc comment

type FilterValue = string | string[] | FilterValueRange

const actionMap = {
equals: '..Equal',
notEqual: '..Not_Equal',
greaterThan: '..Greater',
greaterThanOrEqual: '..Equal_Or_Greater',
lessThan: '..Less',
lessThanOrEqual: '..Equal_Or_Less',
inRange: '..Between',
blank: '..Is_Nothing',
notBlank: '..Not_Nothing',
}

export interface SortFilterNodesButtonOptions {
filterModel: ToValue<{
[key: string]: {
values: any[]
filterType: string
}
}>
filterModel: ToValue<GridFilterModel[]>
sortModel: ToValue<SortModel[]>
isDisabled: ToValue<boolean>
isFilterSortNodeEnabled: ToValue<boolean>
Expand Down Expand Up @@ -65,6 +99,8 @@ function useSortFilterNodesButton({
}

const filterPattern = computed(() => Pattern.parseExpression('__ (__ __)')!)
const filterBetweenPattern = computed(() => Pattern.parseExpression('__ (..Between __ __)')!)
const filterNothingPattern = computed(() => Pattern.parseExpression('__ __')!)

function makeFilterPattern(module: Ast.MutableModule, columnName: string, items: string[]) {
if (
Expand Down Expand Up @@ -97,6 +133,39 @@ function useSortFilterNodesButton({
])
}

function makeNumericFilterPattern(
module: Ast.MutableModule,
columnName: string,
item: string | FilterValueRange,
filterAction: FilterAction,
) {
const valueFormatter = getColumnValueToEnso(columnName)
if (filterAction === 'inRange' && typeof item === 'object') {
const filterToValue = valueFormatter(item.toValue, module)
const filterFromValue = valueFormatter(item.fromValue, module)
return filterBetweenPattern.value.instantiateCopied([
Ast.TextLiteral.new(columnName),
filterFromValue as Expression | MutableExpression,
filterToValue as Expression | MutableExpression,
])
}
const filterValue = valueFormatter(item as string, module)
const action = actionMap[filterAction]
return filterPattern.value.instantiateCopied([
Ast.TextLiteral.new(columnName),
Ast.parseExpression(action)!,
filterValue as Expression | MutableExpression,
])
}

function makeNothingFilterPattern(columnName: string, filterAction: FilterAction) {
const action = actionMap[filterAction]
return filterNothingPattern.value.instantiateCopied([
Ast.TextLiteral.new(columnName),
Ast.parseExpression(action)!,
])
}

function getAstPatternSort() {
return Pattern.new<Ast.Expression>((ast) =>
Ast.App.positional(
Expand All @@ -106,22 +175,62 @@ function useSortFilterNodesButton({
)
}

function getAstPatternFilter(columnName: string, items: string[]) {
function getAstPatternFilter(
columnName: string,
items: string[] | string | FilterValue,
filterType: FilterType,
filterAction?: FilterAction,
) {
return Pattern.new<Ast.Expression>((ast) =>
Ast.App.positional(
Ast.PropertyAccess.new(ast.module, ast, Ast.identifier('filter')!),
filterType === 'set' ?
makeFilterPattern(ast.module, columnName, items as string[])
: makeNumericFilterPattern(ast.module, columnName, items as string | FilterValueRange, filterAction!),
),
)
}

function getAstNothingPatternFilter(columnName: string, filterAction: FilterAction) {
return Pattern.new<Ast.Expression>((ast) =>
Ast.App.positional(
Ast.PropertyAccess.new(ast.module, ast, Ast.identifier('filter')!),
makeFilterPattern(ast.module, columnName, items),
makeNothingFilterPattern(columnName, filterAction),
),
)
}

function getAstPatternFilterAndSort(columnName: string, items: string[]) {
function getAstPatternFilterAndSort(
columnName: string,
items: string[] | string | FilterValueRange,
filterType: FilterType,
filterAction?: FilterAction,
) {
return Pattern.new<Ast.Expression>((ast) =>
Ast.OprApp.new(
ast.module,
Ast.App.positional(
Ast.PropertyAccess.new(ast.module, ast, Ast.identifier('filter')!),
makeFilterPattern(ast.module, columnName, items),
filterType === 'set' ?
makeFilterPattern(ast.module, columnName, items as string[])
: makeNumericFilterPattern(ast.module, columnName, items as string | FilterValueRange, filterAction!),
),
'.',
Ast.App.positional(
Ast.Ident.new(ast.module, Ast.identifier('sort')!),
makeSortPattern(ast.module),
),
),
)
}

function getAstNothingPatternFilterAndSort(columnName: string, filterAction: FilterAction) {
return Pattern.new<Ast.Expression>((ast) =>
Ast.OprApp.new(
ast.module,
Ast.App.positional(
Ast.PropertyAccess.new(ast.module, ast, Ast.identifier('filter')!),
makeNothingFilterPattern(columnName, filterAction),
),
'.',
Ast.App.positional(
Expand All @@ -136,15 +245,44 @@ function useSortFilterNodesButton({
const patterns = new Array<Pattern>()
const filterModelValue = toValue(filterModel)
const sortModelValue = toValue(sortModel)
if (Object.keys(filterModelValue).length) {
for (const [columnName, columnFilter] of Object.entries(filterModelValue)) {
const items = columnFilter.values
const filterPatterns =
sortModelValue.length ?
getAstPatternFilterAndSort(columnName, items)
: getAstPatternFilter(columnName, items)
patterns.push(filterPatterns)
}
if (filterModelValue.length) {
filterModelValue.map((filterModel: GridFilterModel) => {
const columnName = filterModel.columnName
const filterAction = filterModel.filterAction
const filterType = filterModel.filterType
if (filterAction === 'blank' || filterAction === 'notBlank') {
const filterPatterns =
sortModelValue.length ?
getAstNothingPatternFilterAndSort(columnName, filterAction)
: getAstNothingPatternFilter(columnName, filterAction)
patterns.push(filterPatterns)
}

let value: FilterValue
switch (filterType) {
case 'number':
value =
filterAction === 'inRange' ?
{ toValue: filterModel.filterTo!, fromValue: filterModel.filter! }
: (filterModel.filter as FilterValue)
break
case 'date':
value =
filterAction === 'inRange' ?
{ toValue: filterModel.dateTo!, fromValue: filterModel.dateFrom! }
: (filterModel.dateFrom as FilterValue)
break
default:
value = filterModel.values as FilterValue
}
if (value) {
const filterPatterns =
sortModelValue.length ?
getAstPatternFilterAndSort(columnName, value, filterType, filterAction)
: getAstPatternFilter(columnName, value, filterType, filterAction)
patterns.push(filterPatterns)
}
})
} else if (sortModelValue.length) {
patterns.push(getAstPatternSort())
}
Expand Down
Loading