-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(manager-components): update datagrid v6 without iceberg
ref: MANAGER-13931 Signed-off-by: Alex Boungnaseng <alex.boungnaseng.ext@corp.ovh.com>
- Loading branch information
1 parent
2d756eb
commit fb69ad9
Showing
16 changed files
with
775 additions
and
27 deletions.
There are no files selected for viewing
376 changes: 376 additions & 0 deletions
376
packages/manager-components/src/components/datagrid/Filters.tsx
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,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 }; |
5 changes: 5 additions & 0 deletions
5
packages/manager-components/src/components/datagrid/comparator/basic.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,5 @@ | ||
export default class BooleanComparators { | ||
static is(subject, value) { | ||
return subject === value; | ||
} | ||
} |
Oops, something went wrong.