Client:Store: refactoring files store

This commit is contained in:
Timofey Boyko 2024-07-19 11:17:02 +03:00
parent fc3593eab1
commit 41a6083a4b
11 changed files with 1054 additions and 1017 deletions

View File

@ -1,14 +1,957 @@
import { makeAutoObservable, runInAction } from "mobx";
import axios from "axios";
import api from "@docspace/shared/api";
import { TFile, TFolder } from "@docspace/shared/api/files/types";
import { makeAutoObservable } from "mobx";
import FilesFilter, {
TSortBy,
TSortOrder,
} from "@docspace/shared/api/files/filter";
class FilesSelectionStore {
files: TFile[] = [];
import { TRoom } from "@docspace/shared/api/rooms/types";
import RoomsFilter from "@docspace/shared/api/rooms/filter";
folders: TFolder[] = [];
import { toastr } from "@docspace/shared/components/toast";
constructor() {
import { ROOMS_PROVIDER_TYPE_NAME } from "@docspace/shared/constants";
import { isDesktop } from "@docspace/shared/utils";
import { getDaysRemaining, isPublicRoom } from "@docspace/shared/utils/common";
import { SettingsStore } from "@docspace/shared/store/SettingsStore";
import { UserStore } from "@docspace/shared/store/UserStore";
import {
FileStatus,
FilterKeys,
FilterType,
FolderType,
RoomSearchArea,
RoomsProviderType,
RoomsType,
ShareAccessRights,
} from "@docspace/shared/enums";
import {
getCategoryTypeByFolderType,
getCategoryUrl,
} from "SRC_DIR/helpers/utils";
import { CategoryType } from "SRC_DIR/helpers/constants";
import FilesStore from "./FilesStore";
import SelectedFolderStore from "./SelectedFolderStore";
import TreeFoldersStore from "./TreeFoldersStore";
import ClientLoadingStore from "./ClientLoadingStore";
import PublicRoomStore from "./PublicRoomStore";
import InfoPanelStore from "./InfoPanelStore";
import PluginStore from "./PluginStore";
import FilesSettingsStore from "./FilesSettingsStore";
import ThirdPartyStore from "./ThirdPartyStore";
let requestCounter = 0;
const NotFoundHttpCode = 404;
const ForbiddenHttpCode = 403;
const PaymentRequiredHttpCode = 402;
const UnauthorizedHttpCode = 401;
class FilesListStore {
files: Map<string | number, TFile> = new Map();
folders: Map<string | number, TFolder | TRoom> = new Map();
isEmptyPage: boolean = false;
roomsController = new AbortController();
filesController = new AbortController();
constructor(
private settingsStore: SettingsStore,
private selectedFolderStore: SelectedFolderStore,
private treeFoldersStore: TreeFoldersStore,
private clientLoadingStore: ClientLoadingStore,
private userStore: UserStore,
private publicRoomStore: PublicRoomStore,
private infoPanelStore: InfoPanelStore,
private pluginStore: PluginStore,
private filesSettingsStore: FilesSettingsStore,
private thirdPartyStore: ThirdPartyStore,
private filesStore: FilesStore,
) {
makeAutoObservable(this);
}
setIsEmptyPage = (isEmptyPage: boolean) => {
this.isEmptyPage = isEmptyPage;
};
setFile = (file: TFile) => {
if (!this.files.has(file.id)) return;
this.files.set(file.id, file);
this.filesStore.createThumbnail(file);
};
setFiles = (files: TFile[]) => {
const { socketHelper } = this.settingsStore;
if (this.files.size > 0) {
const roomParts = Array.from(this.files.keys()).map((k) => `FILE-${k}`);
socketHelper.emit({
command: "unsubscribe",
data: {
roomParts,
individual: true,
},
});
}
const newFiles: Map<string | number, TFile> = new Map();
const newRoomParts: string[] = [];
files.forEach((value) => {
const key = value.id;
newFiles.set(key, value);
newRoomParts.push(`FILE-${key}`);
});
this.files = newFiles;
if (newRoomParts.length) {
socketHelper.emit({
command: "subscribe",
data: {
roomParts: newRoomParts,
individual: true,
},
});
}
this.filesStore.createThumbnails(files);
};
updateFileStatus = (id: string | number | undefined, status: FileStatus) => {
if (!id) return;
const item = this.files.get(id);
if (item) this.files.set(id, { ...item, fileStatus: status });
};
getFileInfo = async (id: string | number) => {
const fileInfo = await api.files.getFileInfo(id);
this.setFile(fileInfo);
return fileInfo;
};
setFolder = (folder: TRoom | TFolder) => {
if (!this.folders.has(folder.id)) return;
this.folders.set(folder.id, folder);
};
setFolders = (folders: TRoom[] | TFolder[]) => {
const { socketHelper } = this.settingsStore;
if (folders.length === 0) return;
if (this.folders.size > 0) {
const roomParts = Array.from(this.folders.keys()).map((k) => `DIR-${k}`);
socketHelper.emit({
command: "unsubscribe",
data: {
roomParts,
individual: true,
},
});
}
const newFolders: Map<string | number, TRoom | TFolder> = new Map();
const newRoomParts: string[] = [];
folders.forEach((value) => {
const key = value.id;
newFolders.set(key, value);
newRoomParts.push(`DIR-${key}`);
});
this.folders = newFolders;
socketHelper.emit({
command: "subscribe",
data: {
roomParts: newRoomParts,
individual: true,
},
});
};
addFolder = (folder: TRoom | TFolder) => {
const { socketHelper } = this.settingsStore;
const newFolders = new Map([
[folder.id, folder],
...this.folders.entries(),
]);
socketHelper.emit({
command: "subscribe",
data: {
roomParts: `DIR-${folder.id}`,
individual: true,
},
});
this.folders = newFolders;
};
removeFolder = (key: string | number) => {
this.folders.delete(key);
};
updateRoomMute = (id: string | number, mute: boolean) => {
const room = this.folders.get(id);
if (!room) return;
this.folders.set(id, { ...room, mute });
};
getFolderInfo = async (id: string | number) => {
const folderInfo = await api.files.getFolderInfo(id);
this.setFolder(folderInfo);
return folderInfo;
};
clearFiles = () => {
this.files = new Map();
this.folders = new Map();
this.selectedFolderStore.setSelectedFolder(null);
};
abortAllFetch = () => {
this.filesController.abort();
this.roomsController.abort();
this.filesController = new AbortController();
this.roomsController = new AbortController();
};
fetchFiles = async (
folderId: string | number,
filter: FilesFilter,
clearFilter: boolean = true,
withSubfolders: boolean = false,
clearSelection: boolean = true,
) => {
const { setSelectedNode } = this.treeFoldersStore;
if (this.clientLoadingStore.isLoading) {
this.abortAllFetch();
}
const filterData = filter ? filter.clone() : FilesFilter.getDefault();
filterData.folder = folderId;
if (folderId === "@my" && this.userStore.user?.isVisitor) {
const url = getCategoryUrl(CategoryType.Shared);
window.DocSpace.navigate(
`${url}?${RoomsFilter.getDefault().toUrlParams()}`,
);
return;
}
this.filesStore.setIsErrorRoomNotAvailable(false);
const filterStorageItem =
this.userStore.user?.id &&
localStorage.getItem(`UserFilter=${this.userStore.user.id}`);
if (filterStorageItem && !filter) {
const splitFilter = filterStorageItem.split(",");
filterData.sortBy = splitFilter[0] as TSortBy;
filterData.pageCount = +splitFilter[1];
filterData.sortOrder = splitFilter[2] as TSortOrder;
}
if (!this.settingsStore.withPaging) {
filterData.page = 0;
filterData.pageCount = 100;
}
const defaultFilter = FilesFilter.getDefault();
const { filterType, searchInContent } = filterData;
if (typeof filterData.withSubfolders !== "boolean")
filterData.withSubfolders = defaultFilter.withSubfolders;
if (typeof searchInContent !== "boolean")
filterData.searchInContent = defaultFilter.searchInContent;
if (!Object.keys(FilterType).find((key) => FilterType[key] === filterType))
filterData.filterType = defaultFilter.filterType;
setSelectedNode([`${folderId}`]);
try {
const folder = await api.files.getFolder(
folderId,
filterData,
this.filesController.signal,
);
let newTotal = folder.total;
// fixed row loader if total and items length is different
const itemsLength = folder.folders.length + folder.files.length;
if (itemsLength < filterData.pageCount) {
newTotal =
filterData.page > 0
? itemsLength + this.files.size + this.folders.size
: itemsLength;
}
filterData.total = newTotal;
if (
(folder.current.roomType === RoomsType.PublicRoom ||
folder.current.roomType === RoomsType.FormRoom ||
folder.current.roomType === RoomsType.CustomRoom) &&
!this.publicRoomStore.isPublicRoom
) {
await this.publicRoomStore.getExternalLinks(folder.current.id);
}
if (newTotal > 0) {
const lastPage = filterData.getLastPage();
if (filterData.page > lastPage) {
filterData.page = lastPage;
return this.fetchFiles(
folderId,
filterData,
clearFilter,
withSubfolders,
);
}
}
runInAction(() => {
if (!this.publicRoomStore.isPublicRoom) {
this.filesStore.categoryType = getCategoryTypeByFolderType(
folder.current.rootFolderType,
folder.current.parentId,
);
}
});
if (this.filesStore.isPreview) {
// save filter for after closing preview change url
this.filesStore.setTempFilter(filterData);
} else {
this.filesStore.setFilesFilter(filterData); // TODO: FILTER
}
const isPrivacyFolder =
folder.current.rootFolderType === FolderType.Privacy;
let inRoom = false;
const navigationPath = await Promise.all(
folder.pathParts.map(async (f, idx) => {
const { Rooms, Archive } = FolderType;
const isCurrentFolder = folder.current.id === f.id;
const folderInfo = isCurrentFolder
? folder.current
: { ...f, id: f.id };
const { title, roomType } = folderInfo;
inRoom = inRoom || (!!roomType && !isCurrentFolder);
const isRootRoom =
idx === 0 &&
(folder.current.rootFolderType === Rooms ||
folder.current.rootFolderType === Archive);
let shared;
let canCopyPublicLink;
if (idx === 1) {
let room = folder.current;
if (!isCurrentFolder) {
room = await api.files.getFolderInfo(folderId);
shared = room.shared;
canCopyPublicLink =
room.access === ShareAccessRights.RoomManager ||
room.access === ShareAccessRights.None;
if ("canCopyPublicLink" in room)
room.canCopyPublicLink = canCopyPublicLink;
this.infoPanelStore.setInfoPanelRoom(room);
}
const { mute } = room;
runInAction(() => {
this.filesStore.isMuteCurrentRoomNotifications = mute;
});
}
return {
id: folderId,
title,
isRoom: !!roomType,
roomType,
isRootRoom,
shared,
canCopyPublicLink,
};
}),
).then((res) => {
return res
.filter((item, index) => {
return index !== res.length - 1;
})
.reverse();
});
this.selectedFolderStore.setSelectedFolder({
folders: folder.folders,
...folder.current,
inRoom,
isRoom: !!folder.current.roomType,
pathParts: folder.pathParts,
navigationPath,
...{ new: folder.new },
// type,
});
runInAction(() => {
const isEmptyList = [...folder.folders, ...folder.files].length === 0;
if (filter && isEmptyList) {
const {
authorType,
roomId,
search,
withSubfolders: curWithSubFolders,
filterType: curFilterType,
searchInContent: curSearchInContent,
} = filter;
const isFiltered =
authorType ||
roomId ||
search ||
curWithSubFolders ||
curFilterType ||
curSearchInContent;
if (isFiltered) {
this.setIsEmptyPage(false);
} else {
this.setIsEmptyPage(isEmptyList);
}
} else {
this.setIsEmptyPage(isEmptyList);
}
this.setFolders(isPrivacyFolder && !isDesktop() ? [] : folder.folders);
this.setFiles(isPrivacyFolder && !isDesktop() ? [] : folder.files);
});
if (clearFilter) {
if (clearSelection) {
// Find not processed
const tempSelection = this.filesStore.selection.filter(
(f) =>
!this.filesStore.activeFiles.find((elem) => elem.id === f.id),
);
const tempBuffer =
this.filesStore.bufferSelection &&
this.filesStore.activeFiles.find(
(elem) => elem.id === this.filesStore.bufferSelection?.id,
) == null
? this.filesStore.bufferSelection
: null;
// console.log({ tempSelection, tempBuffer });
// Clear all selections
this.filesStore.setSelected("close");
// TODO: see bug 63479
if (this.selectedFolderStore?.id === folderId) {
// Restore not processed
if (tempSelection.length)
this.filesStore.setSelection(tempSelection);
if (tempBuffer) this.filesStore.setBufferSelection(tempBuffer);
}
}
}
this.clientLoadingStore.setIsSectionHeaderLoading(false);
const selectedFolder = {
selectedFolder: { ...this.selectedFolderStore },
};
if (this.filesStore.createdItem) {
const newItem = this.filesList.find(
(item) => item.id === this.filesStore.createdItem?.id,
);
if (newItem) {
this.filesStore.setBufferSelection(newItem);
this.filesStore.setScrollToItem({
id: newItem.id,
type: this.filesStore.createdItem?.type,
});
}
this.filesStore.setCreatedItem(null);
}
if (isPublicRoom()) {
return folder;
}
return selectedFolder;
} catch (err) {
if (err?.response?.status === 402)
this.filesStore.currentTariffStatusStore.setPortalTariff();
const isThirdPartyError = Number.isNaN(+folderId);
if (requestCounter > 0 && !isThirdPartyError) return;
requestCounter = +1;
const isUserError = [
NotFoundHttpCode,
ForbiddenHttpCode,
PaymentRequiredHttpCode,
UnauthorizedHttpCode,
].includes(err?.response?.status);
if (isUserError && !isThirdPartyError) {
this.filesStore.setIsErrorRoomNotAvailable(true);
} else if (axios.isCancel(err)) {
console.log("Request canceled", err.message);
} else {
toastr.error(err);
if (isThirdPartyError) {
const userId = this.userStore?.user?.id;
const searchArea = window.DocSpace.location.pathname.includes(
"shared",
)
? RoomSearchArea.Active
: RoomSearchArea.Archive;
window.DocSpace.navigate(
`${window.DocSpace.location.pathname}?${RoomsFilter.getDefault(userId, searchArea).toUrlParams(userId, true)}`,
);
}
return;
}
} finally {
if (window?.DocSpace?.location?.state?.highlightFileId) {
this.filesStore.setHighlightFile({
highlightFileId: window.DocSpace.location.state.highlightFileId,
isFileHasExst: window.DocSpace.location.state.isFileHasExst,
});
}
}
};
fetchRooms = async (
folderId,
filter,
clearFilter = true,
withSubfolders = false,
clearSelection = true,
withFilterLocalStorage = false,
) => {
const { setSelectedNode } = this.treeFoldersStore;
if (this.clientLoadingStore.isLoading) {
this.abortAllFetch();
}
const filterData = filter
? filter.clone()
: RoomsFilter.getDefault(this.userStore.user?.id);
if (!this.settingsStore.withPaging) {
const isCustomCountPage =
filter && filter.pageCount !== 100 && filter.pageCount !== 25;
if (!isCustomCountPage) {
filterData.page = 0;
filterData.pageCount = 100;
}
}
if (folderId) setSelectedNode([`${folderId}`]);
const defaultFilter = RoomsFilter.getDefault();
const { provider, quotaFilter, type } = filterData;
if (!ROOMS_PROVIDER_TYPE_NAME[provider])
filterData.provider = defaultFilter.provider;
if (
quotaFilter &&
quotaFilter !== FilterKeys.customQuota &&
quotaFilter !== FilterKeys.defaultQuota
)
filterData.quotaFilter = defaultFilter.quotaFilter;
if (type && !RoomsType[type]) filterData.type = defaultFilter.type;
try {
const rooms = await api.rooms.getRooms(
filterData,
this.roomsController.signal,
);
if (!folderId) setSelectedNode([`${rooms.current.id}`]);
filterData.total = rooms.total;
if (rooms.total > 0) {
const lastPage = filterData.getLastPage();
if (filterData.page > lastPage) {
filterData.page = lastPage;
return this.fetchRooms(
folderId,
filterData,
undefined,
undefined,
undefined,
true,
);
}
runInAction(() => {
this.filesStore.categoryType = getCategoryTypeByFolderType(
rooms.current.rootFolderType,
rooms.current.parentId,
);
});
this.filesStore.setRoomsFilter(filterData);
runInAction(() => {
const isEmptyList = rooms.folders.length === 0;
if (filter && isEmptyList) {
const {
subjectId,
filterValue,
type: curType,
withSubfolders: withRoomsSubfolders,
searchInContent: searchInContentRooms,
tags,
withoutTags,
quotaFilter: curQuotaFilter,
provider: curProvider,
} = filter;
const isFiltered =
subjectId ||
filterValue ||
curType ||
curProvider ||
withRoomsSubfolders ||
searchInContentRooms ||
tags ||
withoutTags ||
curQuotaFilter;
if (isFiltered) {
this.setIsEmptyPage(false);
} else {
this.setIsEmptyPage(isEmptyList);
}
} else {
this.setIsEmptyPage(isEmptyList);
}
this.setFolders(rooms.folders);
this.setFiles([]);
if (clearFilter) {
if (clearSelection) {
this.filesStore.setSelected("close");
}
}
this.infoPanelStore.setInfoPanelRoom(null);
this.selectedFolderStore.setSelectedFolder({
folders: rooms.folders,
...rooms.current,
pathParts: rooms.pathParts,
navigationPath: [],
...{ new: rooms.new },
});
this.clientLoadingStore.setIsSectionHeaderLoading(false);
const selectedFolder = {
selectedFolder: { ...this.selectedFolderStore },
};
if (this.filesStore.createdItem) {
const newItem = this.filesStore.filesList.find(
(item) => item.id === this.filesStore.createdItem?.id,
);
if (newItem) {
this.filesStore.setBufferSelection(newItem);
this.filesStore.setScrollToItem({
id: newItem.id,
type: this.filesStore.createdItem?.type,
});
}
this.filesStore.setCreatedItem(null);
}
this.filesStore.setIsErrorRoomNotAvailable(false);
return selectedFolder;
});
}
} catch (err) {
if (err?.response?.status === 402)
this.filesStore.currentTariffStatusStore.setPortalTariff();
if (axios.isCancel(err)) {
console.log("Request canceled", err.message);
} else {
toastr.error(err);
}
}
};
getFilesListItems = (items: (TFile | TFolder | TRoom)[]) => {
const { fileItemsList } = this.pluginStore;
const { enablePlugins } = this.settingsStore;
const { getIcon } = this.filesSettingsStore;
return items.map((item) => {
const { id, rootFolderId, access } = item;
let thirdPartyIcon = "";
let providerType = "";
if ("providerKey" in item) {
thirdPartyIcon = this.thirdPartyStore.getThirdPartyIcon(
item.providerKey,
"small",
);
}
if ("providerKey" in item) {
providerType =
RoomsProviderType[
Object.keys(RoomsProviderType).find(
(key) => key === item.providerKey,
)
];
}
let canOpenPlayer = false;
let needConvert = false;
if ("viewAccessibility" in item) {
canOpenPlayer =
item.viewAccessibility?.ImageView ||
item.viewAccessibility?.MediaView;
needConvert = item.viewAccessibility?.MustConvert;
}
const previewUrl = canOpenPlayer
? this.filesStore.getItemUrl(id, false, needConvert, canOpenPlayer)
: null;
const contextOptions = this.filesStore.getFilesContextOptions(item);
const isThirdPartyFolder =
"providerKey" in item && item.providerKey && id === rootFolderId;
const iconSize = this.filesStore.viewAs === "table" ? 24 : 32;
let isFolder = false;
if ("parentId" in item) {
this.folders.forEach((value) => {
if (value.id === item.id && value.parentId === item.parentId)
isFolder = true;
});
}
const { isRecycleBinFolder } = this.treeFoldersStore;
const folderUrl =
isFolder && this.filesStore.getItemUrl(id, isFolder, false, false);
const isEditing =
"fileStatus" in item && item.fileStatus === FileStatus.IsEditing;
const docUrl =
!canOpenPlayer &&
!isFolder &&
this.filesStore.getItemUrl(id, false, needConvert);
const href = isRecycleBinFolder
? null
: previewUrl || (!isFolder ? docUrl : folderUrl);
const isRoom = "roomType" in item && !!item.roomType;
const logo = "logo" in item ? item.logo : null;
const fileExst = "fileExst" in item ? item.fileExst : undefined;
const providerKey = "providerKey" in item ? item.providerKey : null;
const contentLength =
"contentLength" in item ? item.contentLength : undefined;
const roomType = "roomType" in item ? item.roomType : undefined;
const isArchive = "isArchive" in item ? item.isArchive : undefined;
const type = "type" in item ? item.type : undefined;
const icon =
isRoom && logo?.medium
? logo?.medium
: getIcon(
iconSize,
fileExst,
providerKey,
contentLength,
roomType,
isArchive,
type,
);
const defaultRoomIcon = isRoom
? getIcon(
iconSize,
fileExst,
providerKey,
contentLength,
roomType,
isArchive,
type,
)
: undefined;
const pluginOptions = {
fileTypeName: "",
isPlugin: false,
fileTileIcon: "",
};
if (enablePlugins && fileItemsList) {
fileItemsList.forEach(({ value }) => {
if (value.extension === fileExst) {
if (value.fileTypeName)
pluginOptions.fileTypeName = value.fileTypeName;
pluginOptions.isPlugin = true;
if (value.fileIconTile)
pluginOptions.fileTileIcon = value.fileIconTile;
}
});
}
const isForm = fileExst === ".oform";
const canCopyPublicLink =
access === ShareAccessRights.RoomManager ||
access === ShareAccessRights.None;
return {
...item,
access,
daysRemaining:
"autoDelete" in item &&
item.autoDelete &&
getDaysRemaining(item.autoDelete),
contentLength,
contextOptions,
fileExst,
icon,
defaultRoomIcon,
id,
isFolder,
logo,
rootFolderId,
providerKey,
canOpenPlayer,
previewUrl,
folderUrl,
href,
isThirdPartyFolder,
isEditing,
roomType,
isRoom,
isArchive,
thirdPartyIcon,
providerType,
...pluginOptions,
type,
isForm,
canCopyPublicLink,
};
});
};
get filesList() {
const newFolders = Array.from(this.folders.values());
newFolders.sort((a, b) => {
const firstValue = a.roomType ? 1 : 0;
const secondValue = b.roomType ? 1 : 0;
return secondValue - firstValue;
});
const items = [...newFolders, ...Array.from(this.files.values())];
if (items.length > 0 && this.isEmptyPage) {
this.setIsEmptyPage(false);
}
return this.getFilesListItems(items);
}
}
export default FilesSelectionStore;
export default FilesListStore;

View File

@ -17,6 +17,7 @@ import ClientLoadingStore from "./ClientLoadingStore";
import SelectedFolderStore from "./SelectedFolderStore";
import TreeFoldersStore from "./TreeFoldersStore";
import InfoPanelStore from "./InfoPanelStore";
import FilesListStore from "./FilesListStore";
class FilesSocketStore {
constructor(
@ -27,6 +28,8 @@ class FilesSocketStore {
private infoPanelStore: Readonly<InfoPanelStore>,
private userStore: Readonly<UserStore>,
private filesListStore: Readonly<FilesListStore>,
private filesStore: Readonly<FilesStore>,
) {
makeAutoObservable(this);
@ -157,6 +160,8 @@ class FilesSocketStore {
if (typeof opt === "string") return;
const { fileId, count } = opt;
if (!fileId) return;
const { socketSubscribers } = socketHelper;
const pathParts = `FILE-${fileId}`;
@ -164,46 +169,44 @@ class FilesSocketStore {
console.log(`[WS] markasnew-file ${fileId}:${count}`);
const foundIndex =
fileId && this.filesStore.files.findIndex((x) => x.id === fileId);
this.treeFoldersStore.fetchTreeFolders();
if (foundIndex === -1 || !foundIndex) return;
const fileStatus = this.filesListStore.files.get(fileId)?.fileStatus;
this.filesStore.updateFileStatus(
foundIndex,
typeof count !== "undefined" && Number(count) > 0
? this.filesStore.files[foundIndex].fileStatus | FileStatus.IsNew
: this.filesStore.files[foundIndex].fileStatus & ~FileStatus.IsNew,
);
const status =
typeof count !== "undefined" && Number(count) > 0 && !fileStatus
? FileStatus.IsNew
: fileStatus === FileStatus.IsNew
? FileStatus.None
: fileStatus || FileStatus.None;
if (status !== fileStatus)
this.filesListStore.updateFileStatus(fileId, status);
});
// WAIT FOR RESPONSES OF EDITING FILE
socketHelper.on("s:start-edit-file", (id) => {
if (typeof id !== "string") return;
const { socketSubscribers } = socketHelper;
const pathParts = `FILE-${id}`;
if (!socketSubscribers.has(pathParts)) return;
const foundIndex = this.filesStore.files.findIndex((x) => x.id === id);
if (foundIndex === -1) return;
console.log(`[WS] s:start-edit-file`, id);
console.log(
`[WS] s:start-edit-file`,
id,
this.filesStore.files[foundIndex].title,
);
const fileStatus = this.filesListStore.files.get(id)?.fileStatus;
this.filesStore.updateSelectionStatus(
id,
this.filesStore.files[foundIndex].fileStatus | FileStatus.IsEditing,
fileStatus || FileStatus.IsEditing,
true,
);
this.filesStore.updateFileStatus(
foundIndex,
this.filesStore.files[foundIndex].fileStatus | FileStatus.IsEditing,
this.filesListStore.updateFileStatus(
id,
fileStatus || FileStatus.IsEditing,
);
});
@ -220,6 +223,8 @@ class FilesSocketStore {
});
socketHelper.on("s:stop-edit-file", (id) => {
if (typeof id !== "string") return;
const { socketSubscribers } = socketHelper;
const pathParts = `FILE-${id}`;
@ -228,25 +233,18 @@ class FilesSocketStore {
if (!socketSubscribers.has(pathParts)) return;
const foundIndex = this.filesStore.files.findIndex((x) => x.id === id);
if (foundIndex == -1) return;
console.log(`[WS] s:stop-edit-file`, id);
console.log(
`[WS] s:stop-edit-file`,
id,
this.filesStore.files[foundIndex].title,
);
const currFile = this.filesListStore.files.get(id);
const fileStatus = currFile?.fileStatus;
const status =
fileStatus === FileStatus.IsEditing
? FileStatus.None
: fileStatus || FileStatus.None;
this.filesStore.updateSelectionStatus(
id,
this.filesStore.files[foundIndex].fileStatus & ~FileStatus.IsEditing,
false,
);
this.filesStore.updateSelectionStatus(id, status, false);
this.filesStore.updateFileStatus(
foundIndex,
this.filesStore.files[foundIndex].fileStatus & ~FileStatus.IsEditing,
);
this.filesListStore.updateFileStatus(id, status);
this.filesStore.getFileInfo(id).then((file) => {
if (
@ -258,60 +256,57 @@ class FilesSocketStore {
}
});
this.filesStore.createThumbnail(this.filesStore.files[foundIndex]);
this.filesStore.createThumbnail(currFile);
});
this.filesStore.createNewFilesQueue.on(
"resolve",
this.filesStore.onResolveNewFile,
);
this.filesStore.createNewFilesQueue.on("resolve", this.onResolveNewFile);
}
wsModifyFolderCreate = async (opt: TOptSocket | string) => {
if (typeof opt === "string") return;
if (opt?.type === "file" && opt?.id && opt.data) {
const foundIndex = this.filesStore.files.findIndex(
(x) => x.id === opt?.id,
);
const curFile = this.filesListStore.files.get(opt.id);
const file = JSON.parse(opt?.data);
if (this.selectedFolderStore.id !== file.folderId) {
const movedToIndex = this.filesStore.getFolderIndex(file.folderId);
if (movedToIndex > -1)
this.filesStore.folders[movedToIndex].filesCount++;
const folder = this.filesListStore.folders.get(file.folderId);
if (folder)
this.filesListStore.folders.set(folder.id, {
...folder,
filesCount: folder.filesCount + 1,
});
return;
}
// To update a file version
if (foundIndex > -1 && !this.settingsStore.withPaging) {
if (curFile && !this.settingsStore.withPaging) {
if (
this.filesStore.files[foundIndex].version !== file.version ||
this.filesStore.files[foundIndex].versionGroup !== file.versionGroup
curFile.version !== file.version ||
curFile.versionGroup !== file.versionGroup
) {
this.filesStore.files[foundIndex].version = file.version;
this.filesStore.files[foundIndex].versionGroup = file.versionGroup;
curFile.version = file.version;
curFile.versionGroup = file.versionGroup;
}
this.filesStore.checkSelection(file);
}
if (foundIndex > -1) return;
if (curFile) return;
setTimeout(() => {
const foundIndex = this.filesStore.files.findIndex(
(x) => x.id === file.id,
);
if (foundIndex > -1) {
const foundFile = this.filesListStore.files.get(file.id);
if (foundFile) {
// console.log("Skip in timeout");
return null;
}
this.filesStore.createNewFilesQueue.enqueue(() => {
const foundIndex = this.filesStore.files.findIndex(
(x) => x.id === file.id,
);
if (foundIndex > -1) {
const foundedFile = this.filesListStore.files.get(file.id);
if (foundedFile) {
// console.log("Skip in queue");
return null;
}
@ -319,19 +314,23 @@ class FilesSocketStore {
return api.files.getFileInfo(file.id);
});
}, 300);
} else if (opt?.type === "folder" && opt?.id) {
const foundIndex = this.filesStore.folders.findIndex(
(x) => x.id === opt?.id,
);
} else if (opt?.type === "folder" && opt?.id && opt?.data) {
const curFolder = this.filesListStore.folders.get(opt.id);
if (foundIndex > -1) return;
if (curFolder) return;
const folder = JSON.parse(opt?.data);
if (this.selectedFolderStore.id != folder.parentId) {
const movedToIndex = this.filesStore.getFolderIndex(folder.parentId);
if (movedToIndex > -1)
this.filesStore.folders[movedToIndex].foldersCount++;
if (
this.selectedFolderStore.id?.toString() !== folder.parentId.toString()
) {
const parentFolder = this.filesListStore.folders.get(folder?.parentId);
if (parentFolder)
this.filesListStore.folders.set(parentFolder.id, {
...parentFolder,
filesCount: folder.filesCount + 1,
});
}
if (
@ -340,20 +339,23 @@ class FilesSocketStore {
folder.createdBy.id === this.userStore?.user?.id &&
this.filesStore.roomCreated)
) {
return (this.filesStore.roomCreated = false);
return this.filesStore.setRoomCreated(false);
}
const folderInfo = await api.files.getFolderInfo(folder.id);
console.log("[WS] create new folder", folderInfo.id, folderInfo.title);
const newFolders = [folderInfo, ...this.filesStore.folders];
const newFolders = new Map([
[folder.id, folderInfo],
...this.filesListStore.folders.entries(),
]);
if (
newFolders.length > this.filesStore.filter.pageCount &&
this.filesListStore.folders.size > this.filesStore.filter.pageCount &&
this.settingsStore.withPaging
) {
newFolders.pop(); // Remove last
this.filesListStore.removeFolder(Array.from(newFolders.keys()).pop()); // Remove last
}
const newFilter = this.filesStore.filter;
@ -361,7 +363,7 @@ class FilesSocketStore {
runInAction(() => {
this.filesStore.setFilter(newFilter);
this.filesStore.setFolders(newFolders);
this.filesListStore.addFolder(folderInfo);
});
}
};
@ -383,7 +385,7 @@ class FilesSocketStore {
api.files
.getFolderInfo(folder.id)
.then(this.filesStore.setFolder)
.then(this.filesListStore.setFolder)
.catch(() => {
// console.log("Folder deleted")
});

File diff suppressed because it is too large Load Diff

View File

@ -45,13 +45,13 @@ import { TLogo, TRoomSecurity } from "@docspace/shared/api/rooms/types";
import { setDocumentTitle } from "../helpers/utils";
export type TNavigationPath = {
id: number;
id: number | string;
title: string;
isRoom: boolean;
roomType: RoomsType;
isRootRoom: boolean;
shared: boolean;
canCopyPublicLink: boolean;
roomType?: RoomsType;
isRootRoom?: boolean;
shared?: boolean;
canCopyPublicLink?: boolean;
};
type ExcludeTypes = SettingsStore | Function;
@ -115,6 +115,8 @@ class SelectedFolderStore {
isRoom = false;
inRoom = false;
isArchive = false;
logo: TLogo | null = null;
@ -127,9 +129,7 @@ class SelectedFolderStore {
security: TFolderSecurity | TRoomSecurity | null = null;
type = null;
inRoom = false;
type: FolderType | null = null;
isFolder = true;

View File

@ -297,4 +297,4 @@ class ThirdPartyStore {
}
}
export default new ThirdPartyStore();
export default ThirdPartyStore;

View File

@ -50,7 +50,7 @@ import LdapFormStore from "./LdapFormStore";
import FilesStore from "./FilesStore";
import SelectedFolderStore from "./SelectedFolderStore";
import TreeFoldersStore from "./TreeFoldersStore";
import thirdPartyStore from "./ThirdPartyStore";
import ThirdPartyStore from "./ThirdPartyStore";
import FilesSettingsStore from "./FilesSettingsStore";
import FilesActionsStore from "./FilesActionsStore";
import MediaViewerDataStore from "./MediaViewerDataStore";
@ -84,6 +84,8 @@ import CampaignsStore from "./CampaignsStore";
import OAuthStore from "./OAuthStore";
import FilesSocketStore from "./FilesSocketStore";
const thirdPartyStore = new ThirdPartyStore();
const oauthStore = new OAuthStore(userStore);
const selectedFolderStore = new SelectedFolderStore(settingsStore);

View File

@ -99,7 +99,7 @@ class FilesFilter {
selectedItem: { key?: string | number };
folder: string;
folder: string | number;
searchInContent: boolean | null;

View File

@ -129,7 +129,7 @@ export const enum FilterSubject {
* Enum for filter type.
* @readonly
*/
export const enum FilterType {
export enum FilterType {
None = 0,
FilesOnly = 1,
FoldersOnly = 2,
@ -174,7 +174,7 @@ export const enum FileType {
* Enum for room provider type.
* @readonly
*/
export const enum RoomsProviderType {
export enum RoomsProviderType {
Box = 1,
DropboxV2 = 2,
GoogleDrive = 3,
@ -227,7 +227,7 @@ export const enum PageType {
* Enum for root folders type.
* @readonly
*/
export const enum FolderType {
export enum FolderType {
DEFAULT = 0,
COMMON = 1,
BUNCH = 2,

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { Location, NavigateFunction } from "react-router";
import {
TGetColorTheme,
TSettings,
@ -99,7 +101,8 @@ declare global {
timezone: string;
snackbar?: {};
DocSpace: {
navigate: (path: string, state?: { [key: string]: unknown }) => void;
navigate: NavigateFunction;
location: Location;
};
ClientConfig?: {
pdfViewerUrl: string;

View File

@ -62,7 +62,7 @@ export type TOptSocket = {
export type TEmit = {
command: string;
data: { roomParts: string | []; individual?: boolean };
data: { roomParts: string | string[]; individual?: boolean };
room?: null | boolean;
};