in uui-components/src/pickers/hooks/usePickerList.ts [16:210]
export function usePickerList<TItem, TId, TProps>(props: UsePickerListProps<TItem, TId, TProps>) {
const context = useContext(UuiContext);
const sessionStartTime = useMemo(() => new Date().getTime(), []);
const getMaxTotalItems = () => props.maxTotalItems || 50;
const getMaxDefaultItems = () => Math.min(props.maxDefaultItems || 10, getMaxTotalItems());
const getSettingsKey = () =>
'loveship/PickerList/lastSelectedIds/v2/' + props.settingsKey;
const getSelectedIdsArray = (selected: TId | TId[] | null | undefined): TId[] => {
if (selected) {
if (props.selectionMode === 'single') {
return [selected as TId];
} else {
return selected as TId[];
}
}
return [];
};
const addDistinct = (to: TId[], add: TId[], maxItems: number) => {
const added: Record<string, boolean> = {};
to.forEach((id) => {
added[JSON.stringify(id)] = true;
});
const result = [...to];
for (let n = 0; n < add.length && result.length < maxItems; n++) {
const id = add[n];
const key = JSON.stringify(id);
if (!added[key]) {
result.push(id);
added[key] = true;
}
}
return result;
};
const maxDefaultItems = getMaxDefaultItems();
const getVisibleIds = () => {
let lastUsedUds: TId[] = [];
if (props.settingsKey) {
const settings = context.uuiUserSettings.get(getSettingsKey(), [] as LastUsedRec<TId>[]);
lastUsedUds = settings.map((r) => r.id);
}
let visibleIds: TId[] = getSelectedIdsArray(props.value as TId | TId[]).slice(0, getMaxTotalItems());
visibleIds = addDistinct(visibleIds, [...lastUsedUds, ...(props.defaultIds || [])], maxDefaultItems);
return visibleIds;
};
const pickerListState = usePickerListState<TId>({
dataSourceState: { visibleCount: maxDefaultItems },
visibleIds: getVisibleIds(),
});
const { dataSourceState, setDataSourceState, visibleIds } = pickerListState;
const pickerProps = { ...props, showSelectedOnly: pickerListState.showSelected };
const picker = usePicker<TItem, TId, UsePickerListProps<TItem, TId, TProps>>(pickerProps, pickerListState);
const {
view,
getEntityName,
getPluralName,
getDataSourceState,
isSingleSelect,
getName,
getSelectedRows,
handleDataSourceValueChange,
getRowOptions,
} = picker;
useEffect(() => {
const prevValue = dataSourceStateToValue(props, dataSourceState, props.dataSource);
if (prevValue !== props.value) {
setDataSourceState((state) =>
applyValueToDataSourceState(
props,
state,
props.value,
props.dataSource,
));
}
}, [props.value]);
const onlySelectedView = props.dataSource.useView(getDataSourceState(), handleDataSourceValueChange, {
rowOptions: getRowOptions(),
getSearchFields: props.getSearchFields || ((item: TItem) => [getName(item)]),
...(props.isFoldedByDefault ? { isFoldedByDefault: props.isFoldedByDefault } : {}),
...(props.sortBy ? { sortBy: props.sortBy } : {}),
...(props.cascadeSelection ? { cascadeSelection: props.cascadeSelection } : {}),
...(props.getRowOptions ? { getRowOptions: props.getRowOptions } : {}),
backgroundReload: true,
showSelectedOnly: true,
}, [props.dataSource]);
const getEntityNameForToggler = () => props.entityPluralName || getPluralName();
const getModalTogglerCaption = (totalCount: number, rowsCount: number) => {
let togglerCaption = i18n.pickerList.showAll;
if (totalCount != null) {
togglerCaption += ' ' + totalCount;
}
if (getEntityNameForToggler()) {
togglerCaption += ' ' + getEntityNameForToggler().toUpperCase();
}
if (!isSingleSelect() && rowsCount > 0) {
togglerCaption += i18n.pickerList.rowsSelected(rowsCount);
}
return togglerCaption;
};
const appendLastSelected = (ids: TId[]) => {
if (props.settingsKey) {
let lastUsedIds = context.uuiUserSettings.get(getSettingsKey(), [] as LastUsedRec<TId>[]);
const selectionTime = new Date().getTime();
lastUsedIds = [...ids.map((id) => ({ id, selectionTime, sessionStartTime: sessionStartTime } as LastUsedRec<TId>)).reverse(), ...lastUsedIds].slice(
0,
100,
);
context.uuiUserSettings.set(getSettingsKey(), lastUsedIds);
}
};
const sortRows = (rows: DataRowProps<TItem, TId>[]) => {
const dsState = getDataSourceState();
const sorting = dsState.sorting?.[0];
if (!sorting || (!props.sortBy && !sorting.field)) {
return rows;
}
const sortBy = props.sortBy || ((i: TItem) => i[sorting.field as keyof TItem]);
const sign = sorting.direction === 'desc' ? -1 : 1;
const stringComparer = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare;
const comparer = (a: DataRowProps<TItem, TId>, b: DataRowProps<TItem, TId>) => {
const aIsLoading = (a.isLoading || a.isUnknown);
const bIsLoading = (b.isLoading || b.isUnknown);
const loadingComparison = (bIsLoading ? 0 : 1) - (aIsLoading ? 0 : 1);
if ((loadingComparison && loadingComparison !== 0) || (aIsLoading && bIsLoading)) {
return loadingComparison;
} else {
return sign * stringComparer(sortBy(a.value, sorting), sortBy(b.value, sorting));
}
};
return [...rows].sort(comparer);
};
const buildRowsList = () => {
const maxTotalItems = getMaxTotalItems();
const result: DataRowProps<TItem, TId>[] = [];
const added: Record<string, boolean> = {};
const addRows = (rows: DataRowProps<TItem, TId>[], maxItems: number) => {
for (let n = 0; n < rows.length && (!maxItems || result.length < maxItems); n++) {
const row = rows[n];
if (!added[row.rowKey]) {
result.push(row);
added[row.rowKey] = true;
}
}
};
addRows(getSelectedRows(maxTotalItems), maxTotalItems);
if (visibleIds?.length && result.length < maxTotalItems) {
const rows = visibleIds.map((id, n) => view.getById(id, n));
addRows(rows, maxTotalItems);
}
if (!props.defaultIds && result.length < maxDefaultItems) {
const rows = view.getVisibleRows();
addRows(rows, maxDefaultItems);
}
return sortRows(result);
};
return {
context,
dataSourceState,
getName,
getEntityName,
appendLastSelected,
getSelectedIdsArray,
view,
onlySelectedView,
buildRowsList,
getMaxDefaultItems,
getModalTogglerCaption,
};
}