Skip to content

Commit

Permalink
feat(manager-components): update datagrid v6 without iceberg
Browse files Browse the repository at this point in the history
ref: MANAGER-13931

Signed-off-by: Alex Boungnaseng <alex.boungnaseng.ext@corp.ovh.com>
  • Loading branch information
aboungnaseng-ovhcloud committed Jun 21, 2024
1 parent 2d756eb commit fb69ad9
Show file tree
Hide file tree
Showing 16 changed files with 775 additions and 27 deletions.
376 changes: 376 additions & 0 deletions packages/manager-components/src/components/datagrid/Filters.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,376 @@
import React, { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming';
import {
Column,
ColumnSort as TanstackColumnSort,
PaginationState as TanstackPaginationState,
RowData,
Table,
} from '@tanstack/react-table';
import {
OsdsButton,
OsdsIcon,
OsdsText,
OsdsMenu,
OsdsMenuItem,
OsdsSelect,
OsdsSelectOption,
OsdsInput,
OsdsChip,
} from '@ovhcloud/ods-components/react';
import {
ODS_INPUT_TYPE,
ODS_ICON_NAME,
ODS_ICON_SIZE,
ODS_TEXT_LEVEL,
ODS_TEXT_SIZE,
ODS_BUTTON_VARIANT,
ODS_BUTTON_SIZE,
OsdsInputCustomEvent,
OdsInputValueChangeEventDetail,
} from '@ovhcloud/ods-components';

// import endsWith from 'lodash/endsWith';
// import negate from 'lodash/negate';
import BasicComparators from './comparator/basic';
// import DateComparators from './comparator/date';
import NumberComparators from './comparator/number';
import StringComparators from './comparator/string';

export type ColumnSort = TanstackColumnSort;
export type PaginationState = TanstackPaginationState;

const Filtertrans = {
INCLUDES: 'common_criteria_adder_operator_string_contains',
DOESNT_INCLUDE: 'common_criteria_adder_operator_string_containsNot',
START_WITH: 'common_criteria_adder_operator_string_startsWith',
ENDS_WITH: 'common_criteria_adder_operator_string_endsWith',
EQUALS_TO: 'common_criteria_adder_operator_number_is',
DIFFERENT_FROM: 'common_criteria_adder_operator_boolean_isNot',
};

const comparators = {
boolean: BasicComparators,
// date: DateComparators,
number: NumberComparators,
options: BasicComparators,
string: StringComparators,
};

const resolveComparator = (criterion, type) => {
const baseOperator = criterion.operator.replace(/Not$/, '');
// const negated = endsWith(criterion.operator, 'Not');
const comparator = comparators[type] ? comparators[type][baseOperator] : null;
// return comparator && negated ? negate(comparator) : comparator;
};

const FilterOptions = [
'INCLUDES',
'DOESNT_INCLUDE',
'START_WITH',
'ENDS_WITH',
'EQUALS_TO',
'DIFFERENT_FROM',
];

const ColumnsField = ({ columns, setFilters, filters }: any) => {
const { t } = useTranslation('datagrid');
return (
<>
<div>
<OsdsText
color={ODS_THEME_COLOR_INTENT.text}
level={ODS_TEXT_LEVEL.body}
size={ODS_TEXT_SIZE._200}
>
{t('common_criteria_adder_column_label')}
</OsdsText>
</div>
<div>
<OsdsSelect
required
value={filters.column}
onOdsValueChange={(value) =>
setFilters((previousValue) => ({
column: value.detail.value,
condition: previousValue.condition,
value: previousValue.value,
}))
}
>
{columns
.filter((element: any) => element !== 'iam')
.map((column: any) => (
<OsdsSelectOption key={column.id} value={column.id}>
{column.id}
</OsdsSelectOption>
))}
</OsdsSelect>
</div>
</>
);
};

const ConditionField = ({ setFilters, filters }: any) => {
const { t } = useTranslation('datagrid');
return (
<>
<div>
<OsdsText
color={ODS_THEME_COLOR_INTENT.text}
level={ODS_TEXT_LEVEL.body}
size={ODS_TEXT_SIZE._200}
>
{t('common_criteria_adder_operator_label')}
</OsdsText>
</div>
<div>
<OsdsSelect
required
value={filters.condition}
onOdsValueChange={(value) =>
setFilters((previousValue) => ({
column: previousValue.column,
condition: value.detail.value,
value: previousValue.value,
}))
}
>
{FilterOptions.map((condition: any) => (
<OsdsSelectOption key={condition} value={condition}>
{t(Filtertrans[condition])}
</OsdsSelectOption>
))}
</OsdsSelect>
</div>
</>
);
};

const FiltersCascading = ({
table,
columns,
}: {
table: Table<any>;
columns: any;
}) => {
const { t } = useTranslation('datagrid');
const FieldsByDefault = {
column: columns[0]?.[Object.keys(columns[0])[0]] || '',
condition: FilterOptions[0],
value: '',
};
const [filtersTab, setFiltersTab] = useState([
// {
// column: 'id',
// condition: 'INCLUDES',
// value: 'be',
// },
// {
// column: 'name',
// condition: 'INCLUDES',
// value: 'NICO',
// },
{
column: 'id',
condition: 'START_WITH',
value: 'be',
},
]);
const [filters, setFilters] = useState(FieldsByDefault);
console.info('filtersTab : ', filtersTab);

useEffect(() => {
const tmp = filtersTab?.map((filter) => {
// console.info('filter.condition : ', filter.condition);
if (filter.condition === 'INCLUDES') {
const column = table?.getColumn(filter.column);
// console.info('********************');
// console.info('column : ', column);
// console.info('column.columnDef : ', column.columnDef);
column.setFilterValue(filter.value);
}
if (filter.condition === 'START_WITH') {
const column = table?.getColumn(filter.column);
console.info('********************');
console.info('column : ', column);
// column.columnDef.filterFn = 'startsWith';
// column.columnDef.sortingFn = 'startsWith';
// column.columnDef.aggregationFn = 'startsWith';
console.info('column.columnDef test ALex : ', column.columnDef);
console.info('column : ', column);
console.info('table : ', table);
table?.setColumnFilters([
{ id: filter.column, value: filter.value },
{ id: 'name', value: 'nico' },
]);
// column.setFilterValue(filter.value);
}
return filter;
});
console.info('tmp : ', tmp);
}, [filtersTab]);

return (
<div>
<OsdsMenu>
<OsdsButton
size={ODS_BUTTON_SIZE.sm}
slot={'menu-title'}
color={ODS_THEME_COLOR_INTENT.primary}
variant={ODS_BUTTON_VARIANT.stroked}
>
<span>
<OsdsIcon
name={ODS_ICON_NAME.FILTER}
color={ODS_THEME_COLOR_INTENT.primary}
size={ODS_ICON_SIZE.xxs}
/>
</span>
<span>Filter</span>
</OsdsButton>
<OsdsMenuItem>
<div style={{ width: '200px', padding: '10px' }}>
<div className="pb-4">
<ColumnsField
columns={columns}
setFilters={setFilters}
filters={filters}
/>
</div>
<div className="pb-4">
<ConditionField
columns={columns}
setFilters={setFilters}
filters={filters}
/>
</div>
<div className="pb-4">
<div>
<OsdsText
color={ODS_THEME_COLOR_INTENT.text}
level={ODS_TEXT_LEVEL.body}
size={ODS_TEXT_SIZE._200}
>
{t('common_criteria_adder_value_label')}
</OsdsText>
</div>
<div>
<OsdsInput
type={ODS_INPUT_TYPE.text}
value={filters.value}
onOdsValueChange={(
e: OsdsInputCustomEvent<OdsInputValueChangeEventDetail>,
) =>
setFilters((previousValue) => ({
column: previousValue.column,
condition: previousValue.condition,
value: e.detail.value,
}))
}
/>
</div>
</div>
<div className="pb-4">
<OsdsButton
{...(filters?.value.length > 0 ? {} : { disabled: true })}
size={ODS_BUTTON_SIZE.sm}
color={ODS_THEME_COLOR_INTENT.primary}
onClick={() => {
if (filters?.value.length > 0) {
document.body.click();
setFilters(FieldsByDefault);
setFiltersTab((prev) => [...prev, filters]);
}
}}
>
{t('common_criteria_adder_submit_label')}
</OsdsButton>
</div>
</div>
</OsdsMenuItem>
</OsdsMenu>
<div>
<div className="flex flex-wrap mb-4">
{filtersTab?.map((elem, index) => (
<div key={index} className="w-fit mr-3 mt-4">
<OsdsChip
color={ODS_THEME_COLOR_INTENT.primary}
onOdsChipRemoval={() => {
const column = table?.getColumn(elem.column);
column.setFilterValue('');
setFiltersTab(filtersTab.filter((_, i) => i !== index));
}}
removable
>
<OsdsText>
{elem.column} {elem.condition} {elem.value}
</OsdsText>
</OsdsChip>
</div>
))}
</div>
</div>
</div>
);
};

declare module '@tanstack/react-table' {
// allows us to define custom properties for our columns
interface ColumnMeta<TData extends RowData, TValue> {
filterVariant?: 'text' | 'range' | 'select';
}
}

// A typical debounced input react component
function DebouncedInput({
value: initialValue,
onChange,
debounce = 500,
...props
}: {
value: string | number;
onChange: (value: string | number) => void;
debounce?: number;
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>) {
const [value, setValue] = React.useState(initialValue);

React.useEffect(() => {
setValue(initialValue);
}, [initialValue]);

React.useEffect(() => {
const timeout = setTimeout(() => {
onChange(value);
}, debounce);

return () => clearTimeout(timeout);
}, [value]);

return (
<input
{...props}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
}

function Filter({ column }: { column: Column<any, unknown> }) {
const columnFilterValue = column.getFilterValue();
// const { filterVariant } = column.columnDef.meta ?? {};
const filterVariant = {};

return (
<DebouncedInput
className="w-36 border shadow rounded"
onChange={(value) => column.setFilterValue(value)}
placeholder={`Search Text...`}
type="text"
value={(columnFilterValue ?? '') as string}
/>
);
}

export { FiltersCascading, Filter };
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default class BooleanComparators {
static is(subject, value) {
return subject === value;
}
}
Loading

0 comments on commit fb69ad9

Please sign in to comment.