+type PickerItemPreloadData = {
+ itemId: string;
+ mainItemUuid: string;
+ ancestors: (GroupResource | CollectionResource)[];
+ isHomeProjectItem: boolean;
+}
+
+type PickerTreePreloadData = {
+ tree: Tree<GroupResource | CollectionResource>;
+ pickerTreeId: string;
+ pickerTreeRootUuid: string;
+};
+
+export const loadInitialValue = (pickerItemIds: string[], pickerId: string, includeDirectories: boolean, includeFiles: boolean, multi: boolean,) =>
+ async (dispatch: Dispatch<any>, getState: () => RootState, services: ServiceRepository) => {
+ const homeUuid = getUserUuid(getState());
+
+ // Request ancestor trees in paralell and save home project status
+ const pickerItemsData: PickerItemPreloadData[] = await Promise.allSettled(pickerItemIds.map(async itemId => {
+ const mainItemUuid = itemId.includes('/') ? itemId.split('/')[0] : itemId;
+ const ancestors = (await services.ancestorsService.ancestors(mainItemUuid, ''))
+ .filter(item =>
+ item.kind === ResourceKind.GROUP ||
+ item.kind === ResourceKind.COLLECTION
+ ) as (GroupResource | CollectionResource)[];
+
+ const isHomeProjectItem = !!(homeUuid && ancestors.some(item => item.ownerUuid === homeUuid));
+
+ return {
+ itemId,
+ mainItemUuid,
+ ancestors,
+ isHomeProjectItem,
+ };
+ })).then((res) => {
+ // Show toast if any selections failed to restore
+ if (res.find((promiseResult): promiseResult is PromiseRejectedResult => (promiseResult.status === 'rejected'))) {
+ dispatch<any>(snackbarActions.OPEN_SNACKBAR({ message: `Some selections failed to load and were removed`, kind: SnackbarKind.ERROR }));
+ }
+ // Filter out any failed promises and map to resulting preload data with ancestors
+ return res.filter((promiseResult): promiseResult is PromiseFulfilledResult<PickerItemPreloadData> => (
+ promiseResult.status === 'fulfilled'
+ )).map(res => res.value)
+ });
+
+ // Group items to preload / ancestor data by home/shared picker and create initial Trees to preload
+ const initialTreePreloadData: PickerTreePreloadData[] = [
+ pickerItemsData.filter((item) => item.isHomeProjectItem),
+ pickerItemsData.filter((item) => !item.isHomeProjectItem),
+ ]
+ .filter((items) => items.length > 0)
+ .map((itemGroup) =>
+ itemGroup.reduce(
+ (preloadTree, itemData) => ({
+ tree: createInitialPickerTree(
+ itemData.ancestors,
+ itemData.mainItemUuid,
+ preloadTree.tree
+ ),
+ pickerTreeId: getPickerItemTreeId(itemData, homeUuid, pickerId),
+ pickerTreeRootUuid: getPickerItemRootUuid(itemData, homeUuid),
+ }),
+ {
+ tree: createTree<GroupResource | CollectionResource>(),
+ pickerTreeId: '',
+ pickerTreeRootUuid: '',
+ } as PickerTreePreloadData
+ )
+ );
+
+ // Load initial trees into corresponding picker store
+ await Promise.all(initialTreePreloadData.map(preloadTree => (
+ dispatch(
+ treePickerActions.APPEND_TREE_PICKER_NODE_SUBTREE({
+ id: preloadTree.pickerTreeRootUuid,
+ pickerId: preloadTree.pickerTreeId,
+ subtree: preloadTree.tree,
+ })
+ )
+ )));
+
+ // Await loading collection before attempting to select items
+ await Promise.all(pickerItemsData.map(async itemData => {
+ const pickerTreeId = getPickerItemTreeId(itemData, homeUuid, pickerId);
+
+ // Selected item resides in collection subpath
+ if (itemData.itemId.includes('/')) {
+ // Load collection into tree
+ // loadCollection includes more than dispatched actions and must be awaited
+ await dispatch(loadCollection(itemData.mainItemUuid, pickerTreeId, includeDirectories, includeFiles));
+ }
+ // Expand nodes down to destination
+ dispatch(treePickerActions.EXPAND_TREE_PICKER_NODE_ANCESTORS({ id: itemData.itemId, pickerId: pickerTreeId }));
+ }));
+
+ // Select or activate nodes
+ pickerItemsData.forEach(itemData => {
+ const pickerTreeId = getPickerItemTreeId(itemData, homeUuid, pickerId);
+
+ if (multi) {
+ dispatch(treePickerActions.SELECT_TREE_PICKER_NODE({ id: itemData.itemId, pickerId: pickerTreeId, cascade: false}));
+ } else {
+ dispatch(treePickerActions.ACTIVATE_TREE_PICKER_NODE({ id: itemData.itemId, pickerId: pickerTreeId }));
+ }
+ });
+
+ // Refresh triggers loading in all adjacent items that were not included in the ancestor tree
+ await initialTreePreloadData.map(preloadTree => dispatch(treePickerSearchActions.REFRESH_TREE_PICKER({ pickerId: preloadTree.pickerTreeId })));
+ }
+
+const getPickerItemTreeId = (itemData: PickerItemPreloadData, homeUuid: string | undefined, pickerId: string) => {
+ const { home, shared } = getProjectsTreePickerIds(pickerId);
+ return ((itemData.isHomeProjectItem && homeUuid) ? home : shared);
+};
+
+const getPickerItemRootUuid = (itemData: PickerItemPreloadData, homeUuid: string | undefined) => {
+ return (itemData.isHomeProjectItem && homeUuid) ? homeUuid : SHARED_PROJECT_ID;
+};
+