-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #942 from PrefectHQ/filters-services
UI: Filters Stringify and Parse Services
- Loading branch information
Showing
11 changed files
with
396 additions
and
17 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
orion-ui/packages/orion-design/src/services/FilterDescriptionService.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* eslint-disable default-case */ | ||
import { Filter, FilterObject, FilterProperty } from '../types/filters' | ||
|
||
export class FilterDescriptionService { | ||
public static describe(filter: Filter): string { | ||
const description: string[] = [ | ||
'Show', | ||
this.object(filter.object), | ||
'by', | ||
this.property(filter.property), | ||
] | ||
|
||
|
||
return description.join(' ').trim() | ||
} | ||
|
||
private static object(object: FilterObject): string { | ||
switch (object) { | ||
case 'flow': | ||
return 'flows' | ||
case 'deployment': | ||
return 'deployments' | ||
case 'flow_run': | ||
return 'flow runs' | ||
case 'task_run': | ||
return 'task runs' | ||
case 'tag': | ||
return 'tags' | ||
} | ||
} | ||
|
||
private static property(property: FilterProperty | undefined): string { | ||
switch (property) { | ||
case 'tag': | ||
return 'tag' | ||
case 'name': | ||
return 'name' | ||
case 'start_date': | ||
return 'start date' | ||
case 'state': | ||
return 'state' | ||
case undefined: | ||
return '...' | ||
} | ||
} | ||
} |
137 changes: 137 additions & 0 deletions
137
orion-ui/packages/orion-design/src/services/FilterParseService.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
import { | ||
Filter, | ||
FilterObject, | ||
FilterOperation, | ||
FilterProperty, | ||
FilterType, | ||
FilterValue, | ||
ObjectStringFilter | ||
} from '../types' | ||
import { parseDateTimeNumeric } from '../utilities/dates' | ||
|
||
export class FilterParseService { | ||
|
||
private static readonly dateParsers: ((input: string) => Date)[] = [ | ||
parseDateTimeNumeric, | ||
(input: string) => new Date(input), | ||
] | ||
|
||
public static parseFilterStrings(inputs: string[]): Required<Filter>[] { | ||
return inputs.map(input => this.parseFilterString(input)) | ||
} | ||
|
||
public static parseFilterString(input: string): Required<Filter> { | ||
const [prefix, ...rest] = input.split(':') | ||
const value = rest.join(':') | ||
|
||
switch (prefix) { | ||
case 'd': | ||
case 'deployment': | ||
return this.stringFilter('deployment', 'name', value) | ||
case 'dt': | ||
case 'deployment_tag': | ||
return this.tagFilter('deployment', value) | ||
case 'f': | ||
case 'flow': | ||
return this.stringFilter('flow', 'name', value) | ||
case 'ft': | ||
case 'flow_tag': | ||
return this.tagFilter('flow', value) | ||
case 'fr': | ||
case 'flow_run': | ||
return this.stringFilter('flow_run', 'name', value) | ||
case 'fra': | ||
case 'flow_run_after': | ||
return this.dateFilter('flow_run', 'start_date', 'after', value) | ||
case 'frb': | ||
case 'flow_run_before': | ||
return this.dateFilter('flow_run', 'start_date', 'before', value) | ||
case 'frn': | ||
case 'flow_run_newer': | ||
return this.filter('flow_run', 'start_date', 'time', 'newer', value) | ||
case 'frs': | ||
case 'flow_run_state': | ||
return this.stateFilter('flow_run', 'state', value) | ||
case 'tr': | ||
case 'task_run': | ||
return this.stringFilter('task_run', 'name', value) | ||
case 'tra': | ||
case 'task_run_after': | ||
return this.dateFilter('task_run', 'start_date', 'after', value) | ||
case 'trb': | ||
case 'task_run_before': | ||
return this.dateFilter('task_run', 'start_date', 'before', value) | ||
case 'trn': | ||
case 'task_run_newer': | ||
return this.filter('task_run', 'start_date', 'time', 'newer', value) | ||
case 'trs': | ||
case 'task_run_state': | ||
return this.stateFilter('task_run', 'state', value) | ||
default: | ||
throw 'filter has an invalid prefix' | ||
} | ||
} | ||
|
||
private static stringFilter(object: FilterObject, property: FilterProperty, input: string): Required<Filter> { | ||
const exactOperationRegex = /^"(.*)"$/ | ||
const match = input.match(exactOperationRegex) | ||
|
||
let value: ObjectStringFilter['value'] = input | ||
let operation: ObjectStringFilter['operation'] = 'contains' | ||
|
||
if (match) { | ||
[, value] = match | ||
operation = 'equals' | ||
} | ||
|
||
return this.filter(object, property, 'string', operation, value) | ||
} | ||
|
||
// eslint-disable-next-line max-params | ||
private static dateFilter(object: FilterObject, property: FilterProperty, operation: FilterOperation, input: string): Required<Filter> { | ||
const value = this.parseDateValue(input) | ||
|
||
return this.filter(object, property, 'date', operation, value) | ||
} | ||
|
||
private static tagFilter(object: FilterObject, input: string): Required<Filter> { | ||
return this.filter(object, 'tag', 'tag', 'and', input.split(',')) | ||
} | ||
|
||
private static stateFilter(object: FilterObject, property: FilterProperty, input: string): Required<Filter> { | ||
return this.filter(object, property, 'state', 'or', input.split('|')) | ||
} | ||
|
||
private static parseDateValue(input: string): Date { | ||
let value: Date | ||
const parsers = [...this.dateParsers] | ||
|
||
do { | ||
const parser = parsers.pop()! | ||
value = parser(input) | ||
} while (!this.isValidDate(value) && parsers.length) | ||
|
||
if (!this.isValidDate(value)) { | ||
throw 'filter date value is invalid' | ||
} | ||
|
||
return value | ||
} | ||
|
||
private static isValidDate(input: Date): boolean { | ||
return !isNaN(input.getTime()) | ||
} | ||
|
||
|
||
// eslint-disable-next-line max-params | ||
private static filter(object: FilterObject, property: FilterProperty, type: FilterType, operation: FilterOperation, value: FilterValue): Required<Filter> { | ||
return { | ||
object, | ||
property, | ||
type, | ||
operation, | ||
value, | ||
} as Required<Filter> | ||
} | ||
|
||
} |
30 changes: 30 additions & 0 deletions
30
orion-ui/packages/orion-design/src/services/FilterService.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* eslint-disable no-dupe-class-members */ | ||
import { Filter } from '../types/filters' | ||
import { FilterDescriptionService } from './FilterDescriptionService' | ||
import { FilterParseService, FilterStringifyService } from '.' | ||
|
||
export class FilterService { | ||
public static stringify(filter: Required<Filter>): string | ||
public static stringify(filters: Required<Filter>[]): string[] | ||
public static stringify(filterOrFilters: Required<Filter> | Required<Filter>[]): string | string[] { | ||
if (Array.isArray(filterOrFilters)) { | ||
return FilterStringifyService.convertFiltersToTags(filterOrFilters) | ||
} | ||
|
||
return FilterStringifyService.convertFilterToTag(filterOrFilters) | ||
} | ||
|
||
public static parse(filter: string): Required<Filter> | ||
public static parse(filters: string[]): Required<Filter>[] | ||
public static parse(filterOrFilters: string | string[]): Required<Filter> | Required<Filter>[] { | ||
if (Array.isArray(filterOrFilters)) { | ||
return FilterParseService.parseFilterStrings(filterOrFilters) | ||
} | ||
|
||
return FilterParseService.parseFilterString(filterOrFilters) | ||
} | ||
|
||
public static describe(filter: Filter): string { | ||
return FilterDescriptionService.describe(filter) | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
orion-ui/packages/orion-design/src/services/FilterStringifyService.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/* eslint-disable default-case */ | ||
import { | ||
Filter, | ||
FilterTagPrefix, | ||
ObjectDateFilter, | ||
ObjectStateFilter, | ||
ObjectStringFilter, | ||
ObjectTagFilter, | ||
ObjectTagPrefixDictionary, | ||
ObjectRelativeDateFilter | ||
} from '../types/filters' | ||
import { formatDateTimeNumeric } from '../utilities/dates' | ||
|
||
export class FilterStringifyService { | ||
public static convertFiltersToTags(filters: Required<Filter>[]): string[] { | ||
return filters.map(filter => this.convertFilterToTag(filter)) | ||
} | ||
|
||
public static convertFilterToTag(filter: Required<Filter>): string { | ||
const tagPrefix = this.createTagPrefix(filter) | ||
const tagSuffix = this.createTagSuffix(filter) | ||
const tagValue = this.createTagValue(filter) | ||
|
||
return `${tagPrefix}${tagSuffix}:${tagValue}` | ||
} | ||
|
||
private static createObjectStringFilterValue(filter: ObjectStringFilter): string { | ||
switch (filter.operation) { | ||
case 'contains': | ||
return filter.value | ||
case 'equals': | ||
return `"${filter.value}"` | ||
} | ||
} | ||
|
||
private static createObjectDateFilterValue(filter: ObjectDateFilter): string { | ||
return formatDateTimeNumeric(filter.value) | ||
} | ||
|
||
private static createObjectTimeFilterValue(filter: ObjectRelativeDateFilter): string { | ||
return filter.value | ||
} | ||
|
||
private static createObjectStateFilterValue(filter: ObjectStateFilter): string { | ||
return filter.value.join('|') | ||
} | ||
|
||
private static createObjectTagFilterValue(filter: ObjectTagFilter): string { | ||
return filter.value.join(',') | ||
} | ||
|
||
private static createTagPrefix(filter: Required<Filter>): FilterTagPrefix { | ||
return ObjectTagPrefixDictionary[filter.object] | ||
} | ||
|
||
private static createTagSuffix(filter: Required<Filter>): string { | ||
switch (filter.type) { | ||
case 'string': | ||
return '' | ||
case 'state': | ||
case 'tag': | ||
return filter.type[0] | ||
case 'date': | ||
case 'time': | ||
return filter.operation[0] | ||
} | ||
} | ||
|
||
private static createTagValue(filter: Required<Filter>): string { | ||
switch (filter.type) { | ||
case 'string': | ||
return this.createObjectStringFilterValue(filter) | ||
case 'state': | ||
return this.createObjectStateFilterValue(filter) | ||
case 'tag': | ||
return this.createObjectTagFilterValue(filter) | ||
case 'date': | ||
return this.createObjectDateFilterValue(filter) | ||
case 'time': | ||
return this.createObjectTimeFilterValue(filter) | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
export * from './Api' | ||
export * from './Filter' | ||
export * from './FilterParseService' | ||
export * from './FilterStringifyService' | ||
export * from './LogsApi' | ||
export * from './Mocker' | ||
export * from './SimpleIdManager' | ||
export * from './StatesApi' | ||
export * from './TaskRunsApi' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.