tubular-common
Version:
Tubular Common Models and Data Transformer
152 lines (131 loc) • 6.5 kB
text/typescript
import dayjs from 'dayjs';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import { AggregateFunctions, ColumnDataType, ColumnSortDirection, CompareOperators } from './Column';
import type { ColumnModel } from './ColumnModel';
import type { CompareOperator } from './CompareOperator';
dayjs.extend(customParseFormat);
const normalizaRegex = /([a-z])([A-Z])/g;
const defaultOriginDateFormat = 'YYYY-MM-DD';
const defaultOriginDateTimeFormat = 'YYYY-MM-DDTHH:mm:ss';
const defaultDisplayDateFormat = 'YYYY-MM-DD';
const defaultDisplayDateTimeFormat = 'YYYY-MM-DDTHH:mm:ss';
const defaultComputedCsvValueGetter = () => '';
const getSortDirectionFromOptions = (options: Partial<ColumnModel>): ColumnSortDirection =>
(options.sortable && options.sortDirection) || ColumnSortDirection.None;
const getSortOrder = (sortDirection: ColumnSortDirection, options: Partial<ColumnModel>): number =>
(sortDirection !== ColumnSortDirection.None && options.sortOrder) || -1;
const checkUndefined = (value: unknown, defaultValue = true) => (value === undefined ? defaultValue : value);
export const NumericOperators: CompareOperator[] = [
{ value: CompareOperators.None, title: 'None' },
{ value: CompareOperators.Equals, title: 'Equals' },
{ value: CompareOperators.Between, title: 'Between' },
{ value: CompareOperators.Gte, title: '>=' },
{ value: CompareOperators.Gt, title: '>' },
{ value: CompareOperators.Lte, title: '<=' },
{ value: CompareOperators.Lt, title: '<' },
];
export const StringOperators: CompareOperator[] = [
{ value: CompareOperators.None, title: 'None' },
{ value: CompareOperators.Equals, title: 'Equals' },
{ value: CompareOperators.NotEquals, title: 'Not Equals' },
{ value: CompareOperators.Contains, title: 'Contains' },
{ value: CompareOperators.NotContains, title: 'Not Contains' },
{ value: CompareOperators.StartsWith, title: 'Starts With' },
{ value: CompareOperators.NotStartsWith, title: 'Not Starts With' },
{ value: CompareOperators.EndsWith, title: 'Ends With' },
{ value: CompareOperators.NotEndsWith, title: 'Not Ends With' },
];
export const BooleanOperators: CompareOperator[] = [
{ value: CompareOperators.None, title: 'None' },
{ value: CompareOperators.Equals, title: 'Equals' },
{ value: CompareOperators.NotEquals, title: 'Not Equals' },
];
export const getOperators = (column: ColumnModel): CompareOperator[] => {
switch (column.dataType) {
case ColumnDataType.String:
return StringOperators;
case ColumnDataType.Numeric:
case ColumnDataType.Date:
case ColumnDataType.DateTime:
case ColumnDataType.DateTimeUtc:
return NumericOperators;
case ColumnDataType.Boolean:
return BooleanOperators;
default:
return [];
}
};
const getSortDirection = (sortDirection: ColumnSortDirection) => {
if (sortDirection === ColumnSortDirection.None) return ColumnSortDirection.Ascending;
return sortDirection === ColumnSortDirection.Ascending ? ColumnSortDirection.Descending : ColumnSortDirection.None;
};
export const sortColumnArray = (columnName: string, columns: ColumnModel[], multiSort: boolean) => {
const column = columns.find((c: ColumnModel) => c.name === columnName);
if (!column) {
return undefined;
}
column.sortDirection = getSortDirection(column.sortDirection);
column.sortOrder = column.sortDirection === ColumnSortDirection.None ? -1 : Number.MAX_VALUE;
if (!multiSort) {
// biome-ignore lint/complexity/noForEach: <explanation>
columns
.filter((col: ColumnModel) => col.name !== columnName)
.forEach((c: ColumnModel) => {
c.sortOrder = -1;
c.sortDirection = ColumnSortDirection.None;
});
}
columns
.filter((col: ColumnModel) => col.sortOrder > 0)
.sort((a: ColumnModel, b: ColumnModel) => {
if (a.sortOrder === b.sortOrder) return 0;
return a.sortOrder > b.sortOrder ? 1 : -1;
})
.forEach((col: ColumnModel, i: number) => {
col.sortOrder = i + 1;
});
return columns;
};
export const columnHasFilter = (column: ColumnModel): boolean =>
(!!column.filterText || !!column.filterArgument) && column.filterOperator !== CompareOperators.None;
export const createColumn = (name: string, options?: Partial<ColumnModel>): ColumnModel => {
const temp = options || {};
const sortDirection = getSortDirectionFromOptions(temp);
return {
aggregate: temp.aggregate || AggregateFunctions.None,
dataType: temp.dataType || ColumnDataType.String,
dateDisplayFormat: temp.dateDisplayFormat || defaultDisplayDateFormat,
dateOriginFormat: temp.dateOriginFormat || defaultOriginDateFormat,
dateTimeDisplayFormat: temp.dateTimeDisplayFormat || defaultDisplayDateTimeFormat,
dateTimeOriginFormat: temp.dateTimeOriginFormat || defaultOriginDateTimeFormat,
getComputedStringValue: temp.getComputedStringValue || defaultComputedCsvValueGetter,
isKey: !!temp.isKey,
isComputed: Boolean(checkUndefined(temp.isComputed, false)),
label: temp.label || (name || '').replace(normalizaRegex, '$1 $2'),
name,
searchable: !!temp.searchable,
sortDirection,
sortOrder: getSortOrder(sortDirection, temp),
sortable: !!temp.sortable,
visible: Boolean(checkUndefined(temp.visible)),
filterArgument: temp.filterArgument,
filterOperator: temp.filterOperator,
filterText: temp.filterText,
filterable: Boolean(checkUndefined(temp.filterable, false)),
exportable: Boolean(checkUndefined(temp.exportable)),
};
};
export const isDateColum = (column: ColumnModel): boolean =>
column.dataType === ColumnDataType.Date ||
column.dataType === ColumnDataType.DateTime ||
column.dataType === ColumnDataType.DateTimeUtc;
export const parseDateColumnValue = (column: ColumnModel, value: string): string => {
if (!isDateColum(column) || !value) return '';
switch (column.dataType) {
case ColumnDataType.DateTime:
case ColumnDataType.DateTimeUtc:
return dayjs(value, column.dateTimeOriginFormat).format(column.dateTimeDisplayFormat);
default:
return dayjs(value, column.dateOriginFormat).format(column.dateDisplayFormat);
}
};