Shared:Selectors:Room: rewrite to typescript and move from client
This commit is contained in:
parent
82ad593fcc
commit
a9a8de4722
@ -4,7 +4,7 @@ import { useParams } from "react-router-dom";
|
||||
import { Button } from "@docspace/shared/components/button";
|
||||
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
|
||||
import AppLoader from "@docspace/common/components/AppLoader";
|
||||
import RoomSelector from "../../components/RoomSelector";
|
||||
import RoomSelector from "@docspace/shared/selectors/Room";
|
||||
import FilesSelector from "../../components/FilesSelector";
|
||||
import {
|
||||
frameCallEvent,
|
||||
|
@ -1,21 +0,0 @@
|
||||
import React from "react";
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
|
||||
const SelectorSearchLoader = ({
|
||||
id,
|
||||
className,
|
||||
style,
|
||||
|
||||
...rest
|
||||
}) => {
|
||||
return (
|
||||
<RectangleSkeleton
|
||||
width={"calc(100% - 16px)"}
|
||||
height={"32px"}
|
||||
style={{ padding: "0 0 0 16px", marginBottom: "8px", ...style }}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectorSearchLoader;
|
@ -1,4 +1,3 @@
|
||||
|
||||
import Header from "./HeaderLoader";
|
||||
import SectionHeader from "./SectionHeaderLoader";
|
||||
import ArticleHeader from "./ArticleHeaderLoader";
|
||||
@ -38,8 +37,6 @@ import PaymentsLoader from "./PaymentsLoader";
|
||||
|
||||
import SelectorBreadCrumbsLoader from "./SelectorBreadCrumbsLoader";
|
||||
import PaymentsStandaloneLoader from "./PaymentsStandaloneLoader";
|
||||
import SelectorSearchLoader from "./SelectorSearchLoader";
|
||||
import SelectorRowLoader from "./SelectorRowLoader";
|
||||
|
||||
import InfoPanelViewLoader from "./InfoPanelBodyLoader/InfoPanelViewLoader";
|
||||
import InfoPanelHeaderLoader from "./InfoPanelHeaderLoader";
|
||||
@ -52,7 +49,6 @@ import SettingsDSConnect from "./SettingsLoader/SettingsDSConnectLoader";
|
||||
import EmptyContainerLoader from "./EmptyContainerLoader/EmptyContainerLoader";
|
||||
|
||||
export default {
|
||||
|
||||
Header,
|
||||
SectionHeader,
|
||||
ArticleHeader,
|
||||
@ -91,8 +87,6 @@ export default {
|
||||
|
||||
SelectorBreadCrumbsLoader,
|
||||
PaymentsStandaloneLoader,
|
||||
SelectorSearchLoader,
|
||||
SelectorRowLoader,
|
||||
|
||||
InfoPanelHeaderLoader,
|
||||
InfoPanelViewLoader,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { TUser } from "types";
|
||||
import { TCreatedBy, TPathParts, TUser } from "../../types";
|
||||
import {
|
||||
EmployeeActivationStatus,
|
||||
EmployeeStatus,
|
||||
@ -9,14 +9,6 @@ import {
|
||||
ShareAccessRights,
|
||||
} from "../../enums";
|
||||
|
||||
export type TCreatedBy = {
|
||||
avatarSmall: string;
|
||||
displayName: string;
|
||||
hasAvatar: boolean;
|
||||
id: string;
|
||||
profileUrl: string;
|
||||
};
|
||||
|
||||
export type TFileViewAccessibility = {
|
||||
CanConvert: boolean;
|
||||
CoAuhtoring: boolean;
|
||||
@ -148,12 +140,6 @@ export type TFolder = {
|
||||
|
||||
export type TGetFolderPath = TFolder[];
|
||||
|
||||
export type TPathParts = {
|
||||
id: number;
|
||||
title: string;
|
||||
roomType?: RoomsType;
|
||||
};
|
||||
|
||||
export type TGetFolder = {
|
||||
files: TFile[];
|
||||
folders: TFolder[];
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { AxiosRequestConfig } from "axios";
|
||||
|
||||
import { FolderType } from "../../enums";
|
||||
import { request } from "../client";
|
||||
import {
|
||||
@ -6,8 +8,9 @@ import {
|
||||
toUrlParams,
|
||||
} from "../../utils/common";
|
||||
import RoomsFilter from "./filter";
|
||||
import { TGetRooms } from "./types";
|
||||
|
||||
export function getRooms(filter, signal) {
|
||||
export async function getRooms(filter: RoomsFilter, signal?: AbortSignal) {
|
||||
let params;
|
||||
|
||||
if (filter) {
|
||||
@ -16,24 +19,24 @@ export function getRooms(filter, signal) {
|
||||
params = `?${filter.toApiUrlParams()}`;
|
||||
}
|
||||
|
||||
const options = {
|
||||
const options: AxiosRequestConfig = {
|
||||
method: "get",
|
||||
url: `/files/rooms${params}`,
|
||||
signal,
|
||||
};
|
||||
|
||||
return request(options).then((res) => {
|
||||
res.files = decodeDisplayName(res.files);
|
||||
res.folders = decodeDisplayName(res.folders);
|
||||
const res = (await request(options)) as TGetRooms;
|
||||
|
||||
if (res.current.rootFolderType === FolderType.Archive) {
|
||||
res.folders.forEach((room) => {
|
||||
room.isArchive = true;
|
||||
});
|
||||
}
|
||||
res.files = decodeDisplayName(res.files);
|
||||
res.folders = decodeDisplayName(res.folders);
|
||||
|
||||
return res;
|
||||
});
|
||||
if (res.current.rootFolderType === FolderType.Archive) {
|
||||
res.folders.forEach((room) => {
|
||||
room.isArchive = true;
|
||||
});
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export function getRoomInfo(id) {
|
66
packages/shared/api/rooms/types.ts
Normal file
66
packages/shared/api/rooms/types.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { TFile, TFolder } from "../files/types";
|
||||
import { FolderType, RoomsType, ShareAccessRights } from "../../enums";
|
||||
import { TCreatedBy, TPathParts } from "../../types";
|
||||
|
||||
export type TLogo = {
|
||||
original: string;
|
||||
large: string;
|
||||
medium: string;
|
||||
small: string;
|
||||
color?: string;
|
||||
};
|
||||
|
||||
export type TRoomSecurity = {
|
||||
Read: boolean;
|
||||
Create: boolean;
|
||||
Delete: boolean;
|
||||
EditRoom: boolean;
|
||||
Rename: boolean;
|
||||
CopyTo: boolean;
|
||||
Copy: boolean;
|
||||
MoveTo: boolean;
|
||||
Move: boolean;
|
||||
Pin: boolean;
|
||||
Mute: boolean;
|
||||
EditAccess: boolean;
|
||||
Duplicate: boolean;
|
||||
Download: boolean;
|
||||
CopySharedLink: boolean;
|
||||
};
|
||||
|
||||
export type TRoom = {
|
||||
parentId: number;
|
||||
filesCount: number;
|
||||
foldersCount: number;
|
||||
new: number;
|
||||
mute: boolean;
|
||||
tags: string[];
|
||||
logo: TLogo;
|
||||
pinned: boolean;
|
||||
roomType: RoomsType;
|
||||
private: boolean;
|
||||
inRoom: boolean;
|
||||
id: number;
|
||||
rootFolderId: number;
|
||||
canShare: boolean;
|
||||
title: string;
|
||||
access: ShareAccessRights;
|
||||
shared: boolean;
|
||||
created: Date;
|
||||
createdBy: TCreatedBy;
|
||||
updated: Date;
|
||||
rootFolderType: FolderType;
|
||||
updatedBy: TCreatedBy;
|
||||
isArchive?: boolean;
|
||||
};
|
||||
|
||||
export type TGetRooms = {
|
||||
files: TFile[];
|
||||
folders: TRoom[];
|
||||
current: TFolder;
|
||||
pathParts: TPathParts[];
|
||||
startIndex: number;
|
||||
count: number;
|
||||
total: number;
|
||||
new: number;
|
||||
};
|
16
packages/shared/selectors/Room/RoomSelector.types.ts
Normal file
16
packages/shared/selectors/Room/RoomSelector.types.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { SelectorProps } from "../../components/selector";
|
||||
import { TLogo } from "../../api/rooms/types";
|
||||
import { RoomsType } from "../../enums";
|
||||
|
||||
export interface RoomSelectorProps extends SelectorProps {
|
||||
excludeItems: number[];
|
||||
}
|
||||
|
||||
export type TItem = {
|
||||
id: number;
|
||||
label: string;
|
||||
icon: string;
|
||||
color: string | undefined;
|
||||
logo: TLogo;
|
||||
roomType: RoomsType;
|
||||
};
|
14
packages/shared/selectors/Room/RoomSelector.utils.ts
Normal file
14
packages/shared/selectors/Room/RoomSelector.utils.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { TRoom } from "../../api/rooms/types";
|
||||
|
||||
export const convertToItems = (folders: TRoom[]) => {
|
||||
const items = folders.map((folder) => {
|
||||
const { id, title, roomType, logo } = folder;
|
||||
|
||||
const icon = logo.medium;
|
||||
const color = logo.color;
|
||||
|
||||
return { id, label: title, icon, color, logo, roomType };
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
@ -1,61 +1,26 @@
|
||||
import EmptyScreenCorporateSvgUrl from "PUBLIC_DIR/images/empty_screen_corporate.svg?url";
|
||||
import React from "react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import api from "@docspace/shared/api";
|
||||
import RoomsFilter from "@docspace/shared/api/rooms/filter";
|
||||
import { RoomsType } from "@docspace/shared/enums";
|
||||
import { iconSize32 } from "@docspace/shared/utils/image-helpers";
|
||||
import EmptyScreenCorporateSvgUrl from "PUBLIC_DIR/images/empty_screen_corporate.svg?url";
|
||||
|
||||
import Loaders from "@docspace/common/components/Loaders";
|
||||
import { Selector } from "../../components/selector";
|
||||
import { RowLoader, SearchLoader } from "../../skeletons/selector";
|
||||
import api from "../../api";
|
||||
import RoomsFilter from "../../api/rooms/filter";
|
||||
|
||||
import { Selector } from "@docspace/shared/components/selector";
|
||||
import { TTranslation } from "../../types";
|
||||
|
||||
const pageCount = 100;
|
||||
import { RoomSelectorProps, TItem } from "./RoomSelector.types";
|
||||
import { convertToItems } from "./RoomSelector.utils";
|
||||
|
||||
const getRoomLogo = (roomType) => {
|
||||
let path = "";
|
||||
switch (roomType) {
|
||||
case RoomsType.CustomRoom:
|
||||
path = "custom.svg";
|
||||
break;
|
||||
case RoomsType.FillingFormsRoom:
|
||||
path = "filling.form.svg";
|
||||
break;
|
||||
case RoomsType.EditingRoom:
|
||||
path = "editing.svg";
|
||||
break;
|
||||
case RoomsType.ReadOnlyRoom:
|
||||
path = "view.only.svg";
|
||||
break;
|
||||
case RoomsType.ReviewRoom:
|
||||
path = "review.svg";
|
||||
break;
|
||||
}
|
||||
|
||||
return iconSize32.get(path);
|
||||
};
|
||||
|
||||
const convertToItems = (folders) => {
|
||||
const items = folders.map((folder) => {
|
||||
const { id, title, roomType, logo } = folder;
|
||||
|
||||
const icon = logo.medium ? logo.medium : getRoomLogo(roomType);
|
||||
const color = logo.color;
|
||||
|
||||
return { id, label: title, icon, color, logo, roomType };
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
const PAGE_COUNT = 100;
|
||||
|
||||
const RoomSelector = ({
|
||||
t,
|
||||
id,
|
||||
className,
|
||||
style,
|
||||
|
||||
excludeItems,
|
||||
excludeItems = [],
|
||||
|
||||
headerLabel,
|
||||
onBackClick,
|
||||
@ -91,7 +56,9 @@ const RoomSelector = ({
|
||||
searchEmptyScreenImage,
|
||||
searchEmptyScreenHeader,
|
||||
searchEmptyScreenDescription,
|
||||
}) => {
|
||||
}: RoomSelectorProps) => {
|
||||
const { t }: { t: TTranslation } = useTranslation(["RoomSelector", "Common"]);
|
||||
|
||||
const [isFirstLoad, setIsFirstLoad] = React.useState(true);
|
||||
const [searchValue, setSearchValue] = React.useState("");
|
||||
const [hasNextPage, setHasNextPage] = React.useState(false);
|
||||
@ -99,22 +66,22 @@ const RoomSelector = ({
|
||||
|
||||
const [total, setTotal] = React.useState(0);
|
||||
|
||||
const [items, setItems] = React.useState([]);
|
||||
const [items, setItems] = React.useState<TItem[]>([]);
|
||||
|
||||
const onSearchAction = React.useCallback(
|
||||
(value) => {
|
||||
onSearch && onSearch(value);
|
||||
(value: string) => {
|
||||
onSearch?.(value);
|
||||
setSearchValue(() => {
|
||||
setIsFirstLoad(true);
|
||||
|
||||
return value;
|
||||
});
|
||||
},
|
||||
[onSearch]
|
||||
[onSearch],
|
||||
);
|
||||
|
||||
const onClearSearchAction = React.useCallback(() => {
|
||||
onClearSearch && onClearSearch();
|
||||
onClearSearch?.();
|
||||
setSearchValue(() => {
|
||||
setIsFirstLoad(true);
|
||||
|
||||
@ -123,50 +90,51 @@ const RoomSelector = ({
|
||||
}, [onClearSearch]);
|
||||
|
||||
const onLoadNextPage = React.useCallback(
|
||||
(startIndex) => {
|
||||
async (startIndex: number) => {
|
||||
setIsNextPageLoading(true);
|
||||
|
||||
const page = startIndex / pageCount;
|
||||
const page = startIndex / PAGE_COUNT;
|
||||
|
||||
const filter = RoomsFilter.getDefault();
|
||||
|
||||
filter.page = page;
|
||||
filter.pageCount = pageCount;
|
||||
filter.pageCount = PAGE_COUNT;
|
||||
|
||||
filter.filterValue = searchValue ? searchValue : null;
|
||||
filter.filterValue = searchValue || null;
|
||||
|
||||
api.rooms
|
||||
.getRooms(filter)
|
||||
.then(({ folders, total, count }) => {
|
||||
const rooms = convertToItems(folders);
|
||||
const {
|
||||
folders,
|
||||
total: totalCount,
|
||||
count,
|
||||
} = await api.rooms.getRooms(filter);
|
||||
|
||||
const itemList = rooms.filter((x) => !excludeItems.includes(x.id));
|
||||
const rooms = convertToItems(folders);
|
||||
|
||||
setHasNextPage(count === pageCount);
|
||||
const itemList = rooms.filter((x) => !excludeItems.includes(x.id));
|
||||
|
||||
if (isFirstLoad) {
|
||||
setTotal(total);
|
||||
setItems(itemList);
|
||||
} else {
|
||||
setItems((value) => [...value, ...itemList]);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (isFirstLoad) {
|
||||
setTimeout(() => {
|
||||
setIsFirstLoad(false);
|
||||
}, 500);
|
||||
}
|
||||
setHasNextPage(count === PAGE_COUNT);
|
||||
|
||||
setIsNextPageLoading(false);
|
||||
});
|
||||
if (isFirstLoad) {
|
||||
setTotal(totalCount);
|
||||
setItems(itemList);
|
||||
} else {
|
||||
setItems((value) => [...value, ...itemList]);
|
||||
}
|
||||
|
||||
if (isFirstLoad) {
|
||||
setTimeout(() => {
|
||||
setIsFirstLoad(false);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
setIsNextPageLoading(false);
|
||||
},
|
||||
[isFirstLoad, excludeItems, searchValue]
|
||||
[isFirstLoad, excludeItems, searchValue],
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
onLoadNextPage(0);
|
||||
}, [searchValue]);
|
||||
}, [onLoadNextPage, searchValue]);
|
||||
|
||||
return (
|
||||
<Selector
|
||||
@ -216,9 +184,9 @@ const RoomSelector = ({
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
loadNextPage={onLoadNextPage}
|
||||
isLoading={isFirstLoad}
|
||||
searchLoader={<Loaders.SelectorSearchLoader />}
|
||||
searchLoader={<SearchLoader />}
|
||||
rowLoader={
|
||||
<Loaders.SelectorRowLoader
|
||||
<RowLoader
|
||||
isMultiSelect={isMultiSelect}
|
||||
isContainer={isFirstLoad}
|
||||
isUser={false}
|
||||
@ -228,6 +196,4 @@ const RoomSelector = ({
|
||||
);
|
||||
};
|
||||
|
||||
RoomSelector.defaultProps = { excludeItems: [] };
|
||||
|
||||
export default withTranslation(["RoomSelector", "Common"])(RoomSelector);
|
||||
export default RoomSelector;
|
@ -12,4 +12,5 @@ export interface RectangleSkeletonProps {
|
||||
foregroundOpacity?: number;
|
||||
speed?: number;
|
||||
animate?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import { RectangleSkeleton } from "@docspace/shared/skeletons";
|
||||
import { RectangleSkeleton, RectangleSkeletonProps } from "../rectangle";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
@ -13,7 +13,7 @@ const StyledContainer = styled.div`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const StyledItem = styled.div`
|
||||
const StyledItem = styled.div<{ isUser?: boolean }>`
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
min-height: 48px;
|
||||
@ -52,7 +52,18 @@ const Divider = styled.div`
|
||||
border-bottom: ${(props) => props.theme.selector.border};
|
||||
`;
|
||||
|
||||
const SelectorRowLoader = ({
|
||||
interface RowLoaderProps extends RectangleSkeletonProps {
|
||||
id?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
isMultiSelect?: boolean;
|
||||
isContainer?: boolean;
|
||||
isUser?: boolean;
|
||||
withAllSelect?: boolean;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
const RowLoader = ({
|
||||
id,
|
||||
className,
|
||||
style,
|
||||
@ -62,30 +73,21 @@ const SelectorRowLoader = ({
|
||||
withAllSelect,
|
||||
count = 5,
|
||||
...rest
|
||||
}) => {
|
||||
const getRowItem = (key) => {
|
||||
}: RowLoaderProps) => {
|
||||
const getRowItem = (key: number) => {
|
||||
return (
|
||||
<StyledItem
|
||||
id={id}
|
||||
className={className}
|
||||
style={style}
|
||||
isMultiSelect={isMultiSelect}
|
||||
isUser={isUser}
|
||||
key={key}
|
||||
{...rest}
|
||||
>
|
||||
<RectangleSkeleton
|
||||
className={"avatar"}
|
||||
width={"32px"}
|
||||
height={"32px"}
|
||||
/>
|
||||
<RectangleSkeleton width={"212px"} height={"16px"} />
|
||||
<RectangleSkeleton className="avatar" width="32px" height="32px" />
|
||||
<RectangleSkeleton width="212px" height="16px" />
|
||||
{isMultiSelect && (
|
||||
<RectangleSkeleton
|
||||
className={"checkbox"}
|
||||
width={"16px"}
|
||||
height={"16px"}
|
||||
/>
|
||||
<RectangleSkeleton className="checkbox" width="16px" height="16px" />
|
||||
)}
|
||||
</StyledItem>
|
||||
);
|
||||
@ -93,7 +95,7 @@ const SelectorRowLoader = ({
|
||||
|
||||
const getRowItems = () => {
|
||||
const rows = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
for (let i = 0; i < count; i += 1) {
|
||||
rows.push(getRowItem(i));
|
||||
}
|
||||
|
||||
@ -111,8 +113,8 @@ const SelectorRowLoader = ({
|
||||
{getRowItems()}
|
||||
</StyledContainer>
|
||||
) : (
|
||||
getRowItem()
|
||||
getRowItem(0)
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectorRowLoader;
|
||||
export default RowLoader;
|
27
packages/shared/skeletons/selector/Search.tsx
Normal file
27
packages/shared/skeletons/selector/Search.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import { RectangleSkeleton, RectangleSkeletonProps } from "../rectangle";
|
||||
|
||||
interface SearchLoaderProps extends RectangleSkeletonProps {
|
||||
id?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
const SearchLoader = ({
|
||||
id,
|
||||
className,
|
||||
style,
|
||||
|
||||
...rest
|
||||
}: SearchLoaderProps) => {
|
||||
return (
|
||||
<RectangleSkeleton
|
||||
width="calc(100% - 16px)"
|
||||
height="32px"
|
||||
style={{ padding: "0 0 0 16px", marginBottom: "8px", ...style }}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchLoader;
|
4
packages/shared/skeletons/selector/index.ts
Normal file
4
packages/shared/skeletons/selector/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import RowLoader from "./Row";
|
||||
import SearchLoader from "./Search";
|
||||
|
||||
export { SearchLoader, RowLoader };
|
@ -14,6 +14,7 @@
|
||||
"hooks",
|
||||
"api",
|
||||
"sw",
|
||||
"selectors",
|
||||
// add all files in which you see
|
||||
// the "parserOptions.project" error
|
||||
".eslintrc.cjs",
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { RoomsType } from "../enums";
|
||||
import { TTheme } from "../themes";
|
||||
|
||||
export type TDirectionX = "left" | "right";
|
||||
@ -9,6 +10,20 @@ export type TTranslation = (key: string) => string;
|
||||
|
||||
export type { TUser } from "./user";
|
||||
|
||||
export type TPathParts = {
|
||||
id: number;
|
||||
title: string;
|
||||
roomType?: RoomsType;
|
||||
};
|
||||
|
||||
export type TCreatedBy = {
|
||||
avatarSmall: string;
|
||||
displayName: string;
|
||||
hasAvatar: boolean;
|
||||
id: string;
|
||||
profileUrl: string;
|
||||
};
|
||||
|
||||
export type TI18n = {
|
||||
language: string;
|
||||
changeLanguage: (l: string) => string;
|
||||
|
@ -28,6 +28,7 @@ import { FolderType, RoomsType, ThemeKeys } from "../enums";
|
||||
import { LANGUAGE, RTL_LANGUAGES } from "../constants";
|
||||
import { TUser, TI18n } from "../types";
|
||||
import { TFolder, TFile, TGetFolder } from "../api/files/types";
|
||||
import { TRoom } from "../api/rooms/types";
|
||||
import TopLoaderService from "../components/top-loading-indicator";
|
||||
|
||||
import { Encoder } from "./encoder";
|
||||
@ -594,7 +595,9 @@ export const getFolderClassNameByType = (folderType: FolderType) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const decodeDisplayName = <T extends TFile | TFolder>(items: T[]) => {
|
||||
export const decodeDisplayName = <T extends TFile | TFolder | TRoom>(
|
||||
items: T[],
|
||||
) => {
|
||||
return items.map((item) => {
|
||||
if (!item) return item;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user