Merge branch 'hotfix/v2.0.1' into develop

This commit is contained in:
Alexey Safronov 2023-12-13 20:01:17 +04:00
commit 69d3dadc13
108 changed files with 956 additions and 332 deletions

3
.github/codeql/config-codeql.yml vendored Normal file
View File

@ -0,0 +1,3 @@
---
paths:
- ./**

67
.github/workflows/codeql.yaml vendored Normal file
View File

@ -0,0 +1,67 @@
name: "CodeQL"
on:
push:
branches:
- 'master'
- 'release/**'
- 'hotfix/**'
paths-ignore:
- '**/README.md'
- '**/LICENSE'
- '.github/**'
pull_request:
# The branches below must be a subset of the branches above
branches:
- 'master'
- 'release/**'
- 'hotfix/**'
paths-ignore:
- '**/README.md'
- '**/LICENSE'
- '.github/**'
schedule:
- cron: '45 3 * * 5'
jobs:
analyze:
name: Analyze
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners
# Consider using larger runners for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'javascript' ]
# CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ]
# Use only 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout client
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
config-file: .github/codeql/config-codeql.yml
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

View File

@ -1,6 +1,6 @@
{
"name": "docspace",
"version": "2.0.0",
"version": "2.0.1",
"private": true,
"workspaces": {
"packages": [

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/client",
"version": "2.0.0",
"version": "2.0.1",
"private": true,
"homepage": "",
"scripts": {

View File

@ -1,6 +1,6 @@
{
"AddedToClipboard": "項目は、クリップボードに追加されました",
"AdditionalLinks": "추가 링크",
"AdditionalLinks": "追加リンク",
"AddMembersDescription": "新しいチームメンバーを手動で追加したり、リンクで招待したりすることができます。",
"AddNewLink": "新しいリンクの追加",
"All": "すべて",

View File

@ -35,7 +35,7 @@ export default function withContent(WrappedContent) {
}
getStatusByDate = (create) => {
const { culture, item, personal } = this.props;
const { culture, item } = this.props;
const { created, updated } = item;
const locale = getCookie(LANGUAGE) || culture;

View File

@ -1,4 +1,4 @@
import React, { useEffect } from "react";
import { useEffect, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { observer, inject } from "mobx-react";
import { useNavigate } from "react-router-dom";
@ -67,17 +67,24 @@ const withHotkeys = (Component) => {
const navigate = useNavigate();
const [isEnabled, setIsEnabled] = useState(true);
const hotkeysFilter = {
filter: (ev) =>
ev.target?.type === "checkbox" || ev.target?.tagName !== "INPUT",
filterPreventDefault: false,
enableOnTags: ["INPUT"],
enabled: enabledHotkeys && !mediaViewerIsVisible && !filesIsLoading,
enabled:
enabledHotkeys && !mediaViewerIsVisible && !filesIsLoading && isEnabled,
// keyup: true,
// keydown: false,
};
const onKeyDown = (e) => activateHotkeys(e);
const onKeyDown = (e) => {
const someDialogIsOpen = checkDialogsOpen();
setIsEnabled(!someDialogIsOpen);
activateHotkeys(e);
};
const folderWithNoAction =
isFavoritesFolder ||

View File

@ -18,7 +18,7 @@ import { I18nextProvider, useTranslation } from "react-i18next";
import i18n from "./i18n";
import Snackbar from "@docspace/components/snackbar";
import moment from "moment";
import moment from "moment-timezone";
//import ReactSmartBanner from "./components/SmartBanner";
import { useThemeDetector } from "@docspace/common/utils/useThemeDetector";
import { isMobile, isIOS, isFirefox } from "react-device-detect";
@ -54,7 +54,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
standalone,
userId,
currentDeviceType,
timezone,
showArticleLoader,
} = rest;
@ -484,11 +484,15 @@ const ThemeProviderWrapper = inject(({ auth, loginStore }) => {
currentColorScheme = settingsStore.currentColorScheme || false;
}
const { timezone } = settingsStore;
window.theme = theme;
window.timezone = timezone;
return {
theme: { ...theme, interfaceDirection: i18n.dir() },
currentColorScheme,
timezone,
};
})(observer(ThemeProvider));

View File

@ -139,7 +139,7 @@ const Item = ({
labelBadge={labelBadge}
onClickBadge={onBadgeClick}
iconBadge={iconBadge}
badgeTitle={t("RecycleBinAction")}
badgeTitle={labelBadge ? "" : t("RecycleBinAction")}
/>
</StyledDragAndDrop>
);

View File

@ -11,6 +11,8 @@ import Mute16ReactSvgUrl from "PUBLIC_DIR/images/icons/16/mute.react.svg?url";
import React, { useState } from "react";
import styled from "styled-components";
import { isMobile as isMobileDevice } from "react-device-detect";
import Badge from "@docspace/components/badge";
import IconButton from "@docspace/components/icon-button";
import commonIconsStyles from "@docspace/components/utils/common-icons-style";
@ -23,7 +25,7 @@ import {
import { Base } from "@docspace/components/themes";
import { ColorTheme, ThemeType } from "@docspace/components/ColorTheme";
import { isTablet, isDesktop } from "@docspace/components/utils/device";
import { isTablet, isDesktop, size } from "@docspace/components/utils/device";
import { classNames } from "@docspace/components/utils/classNames";
const StyledWrapper = styled.div`
@ -114,7 +116,10 @@ const Badges = ({
const contentNewItems = newItems > 999 ? "999+" : newItems;
const tabletViewBadge = !isTile && isTablet();
const isLargeTabletDevice =
isMobileDevice && window.innerWidth >= size.desktop;
const tabletViewBadge = !isTile && (isTablet() || isLargeTabletDevice);
const desktopView = !isTile && isDesktop();
const sizeBadge = isTile || tabletViewBadge ? "medium" : "small";

View File

@ -71,6 +71,7 @@ export type useRootHelperProps = {
onSetBaseFolderPath?: (
value: number | string | undefined | BreadCrumb[]
) => void;
isUserOnly?: boolean;
};
export type useRoomsHelperProps = {
@ -129,6 +130,7 @@ export type FilesSelectorProps = {
isThirdParty: boolean;
rootThirdPartyId?: string;
isRoomsOnly: boolean;
isUserOnly: boolean;
isRoomBackup: boolean;
isEditorDialog: boolean;
setMoveToPublicRoomVisible: (visible: boolean, operationData: object) => void;
@ -217,5 +219,6 @@ export type FilesSelectorProps = {
embedded: boolean;
withHeader: boolean;
withCancelButton: boolean;
settings: any;
};

View File

@ -20,6 +20,7 @@ const useRootHelper = ({
setIsNextPageLoading,
setTotal,
setHasNextPage,
isUserOnly,
}: useRootHelperProps) => {
const [isRoot, setIsRoot] = React.useState<boolean>(false);
@ -41,7 +42,7 @@ const useRootHelper = ({
const avatar = getCatalogIconUrlByType(folder.rootFolderType);
if (
folder.rootFolderType === FolderType.Rooms ||
(!isUserOnly && folder.rootFolderType === FolderType.Rooms) ||
folder.rootFolderType === FolderType.USER
) {
newItems.push({

View File

@ -38,6 +38,7 @@ const FilesSelector = ({
// withoutImmediatelyClose = false,
isThirdParty = false,
isRoomsOnly = false,
isUserOnly = false,
isEditorDialog = false,
rootThirdPartyId,
@ -100,6 +101,7 @@ const FilesSelector = ({
embedded,
withHeader,
withCancelButton = true,
getIcon,
isRoomBackup,
}: FilesSelectorProps) => {
@ -164,6 +166,7 @@ const FilesSelector = ({
setHasNextPage,
setIsNextPageLoading,
onSetBaseFolderPath,
isUserOnly,
});
const { getRoomList } = useRoomsHelper({
@ -523,7 +526,7 @@ const FilesSelector = ({
onSelect={onSelectAction}
acceptButtonLabel={acceptButtonLabel}
onAccept={onAcceptAction}
withCancelButton
withCancelButton={withCancelButton}
cancelButtonLabel={t("Common:CancelButton")}
onCancel={onCloseAction}
emptyScreenImage={
@ -567,7 +570,9 @@ const FilesSelector = ({
currentFooterInputValue={currentFooterInputValue}
footerCheckboxLabel={footerCheckboxLabel}
descriptionText={
!filterParam ? "" : descriptionText ?? t("Common:SelectDOCXFormat")
!filterParam || filterParam === "ALL"
? ""
: descriptionText ?? t("Common:SelectDOCXFormat")
}
acceptButtonId={
isMove || isCopy || isRestore ? "select-file-modal-submit" : ""

View File

@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { CreateRoomDialog } from "../dialogs";
const CreateRoomEvent = ({
title,
visible,
onClose,
@ -57,6 +58,7 @@ const CreateRoomEvent = ({
return (
<CreateRoomDialog
title={title}
t={t}
visible={
visible &&

View File

@ -31,6 +31,7 @@ const GlobalEvents = ({ enablePlugins, eventListenerItemsList }) => {
});
const [createRoomDialogProps, setCreateRoomDialogProps] = useState({
title: "",
visible: false,
onClose: null,
});
@ -101,9 +102,10 @@ const GlobalEvents = ({ enablePlugins, eventListenerItemsList }) => {
const onCreateRoom = useCallback((e) => {
setCreateRoomDialogProps({
title: e?.title,
visible: true,
onClose: () =>
setCreateRoomDialogProps({ visible: false, onClose: null }),
setCreateRoomDialogProps({ title: "", visible: false, onClose: null }),
});
}, []);

View File

@ -107,6 +107,8 @@ const Layout = (props) => {
};
const onScroll = (e) => {
if (window.innerHeight < window.innerWidth) return;
e.preventDefault();
e.stopPropagation();
window.scrollTo(0, 0);

View File

@ -33,7 +33,7 @@ const StyledMain = styled.main`
`;
const Main = (props) => {
const { mainBarVisible, isBannerVisible } = props;
const { mainBarVisible, isBannerVisible, isFrame } = props;
//console.log("Main render");
const [mainHeight, setMainHeight] = React.useState(window.innerHeight);
const updateSizeRef = React.useRef(null);
@ -51,7 +51,7 @@ const Main = (props) => {
React.useEffect(() => {
onResize();
}, [mainBarVisible, isBannerVisible]);
}, [mainBarVisible, isBannerVisible, isFrame]);
const onResize = React.useCallback(
(e) => {
@ -89,13 +89,13 @@ const Main = (props) => {
}
// 48 - its nav menu with burger, logo and user avatar
if (isMobileUtils()) {
if (isMobileUtils() && !isFrame) {
correctHeight -= 48;
}
setMainHeight(correctHeight);
},
[mainBarVisible, isBannerVisible]
[mainBarVisible, isBannerVisible, isFrame]
);
return <StyledMain className="main" mainHeight={mainHeight} {...props} />;
@ -106,9 +106,10 @@ Main.displayName = "Main";
export default inject(({ auth }) => {
const { isBannerVisible } = auth.bannerStore;
const { mainBarVisible } = auth.settingsStore;
const { mainBarVisible, isFrame } = auth.settingsStore;
return {
mainBarVisible,
isBannerVisible,
isFrame,
};
})(observer(Main));

View File

@ -43,7 +43,7 @@ const convertToItems = (folders) => {
const icon = logo.medium ? logo.medium : getRoomLogo(roomType);
const color = logo.color;
return { id, label: title, icon, color };
return { id, label: title, icon, color, logo, roomType };
});
return items;

View File

@ -35,6 +35,7 @@ const StyledModalDialog = styled(ModalDialog)`
const CreateRoomDialog = ({
t,
visible,
title,
onClose,
onCreate,
@ -59,7 +60,7 @@ const CreateRoomDialog = ({
const startRoomParams = {
type: undefined,
title: "",
title: title,
tags: [],
isPrivate: false,
storageLocation: {
@ -93,7 +94,7 @@ const CreateRoomDialog = ({
}));
};
const isRoomTitleChanged = roomParams.title.trim() !== "" ? false : true;
const isRoomTitleChanged = roomParams?.title?.trim() !== "" ? false : true;
const onKeyUpHandler = (e) => {
if (isWrongTitle) return;
@ -101,7 +102,7 @@ const CreateRoomDialog = ({
};
const onCreateRoom = async () => {
if (!roomParams.title.trim()) {
if (!roomParams?.title?.trim()) {
setIsValidTitle(false);
return;
}

View File

@ -87,7 +87,11 @@ const DeleteLinkDialogComponent = (props) => {
<Button
id="delete-file-modal_submit"
key="OkButton"
label={t("Common:Delete")}
label={
link.sharedTo.primary && isPublicRoomType
? t("Files:RevokeLink")
: t("Files:DeleteLink")
}
size="normal"
primary
scale

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation, Trans } from "react-i18next";
import { useNavigate } from "react-router-dom";
import moment from "moment";
import moment from "moment-timezone";
import ModalDialog from "@docspace/components/modal-dialog";
import Button from "@docspace/components/button";
import Text from "@docspace/components/text";
@ -32,9 +32,10 @@ const InviteUsersWarningDialog = (props) => {
useEffect(() => {
moment.locale(language);
if (window.timezone) moment().tz(window.timezone);
gracePeriodDays();
}, [language, gracePeriodDays]);
}, [language, gracePeriodDays, window.timezone]);
const gracePeriodDays = () => {
const fromDateMoment = moment(dueDate);

View File

@ -130,7 +130,7 @@ export default inject(({ auth, pluginStore }) => {
const plugin = pluginList.find((p) => p.name === pluginName);
const withDelete = pluginOptions.includes("delete") && !plugin.system;
const withDelete = pluginOptions.delete && !plugin.system;
const pluginSettings = plugin?.getAdminPluginSettings();

View File

@ -17,7 +17,6 @@ const EmbeddingBody = ({ t, link, requestToken, roomId }) => {
const [heightValue, setHeightValue] = useState("100%");
const config = {
hash: `${API_JS_HASH}`,
width: `${widthValue}`,
height: `${heightValue}`,
frameId: "ds-frame-embedding",

View File

@ -63,7 +63,7 @@ const ExternalLinks = ({
const editLink = async () => {
const type =
roomType === RoomsType.PublicRoom
? ShareAccessRights.RoomManager
? ShareAccessRights.Collaborator
: ShareAccessRights.ReadOnly;
const link = await setInvitationLinks(roomId, "Invite", type);

View File

@ -138,6 +138,8 @@ export const getCategoryType = (location) => {
categoryType = CategoryType.Settings;
} else if (pathname.startsWith("/accounts/filter")) {
categoryType = CategoryType.Accounts;
} else if (pathname.startsWith("/form-gallery")) {
categoryType = CategoryType.Personal;
}
return categoryType;

View File

@ -10,7 +10,7 @@ const Error401 = ({}) => {
return <ErrorContainer headerText={t("Error401Text")} />;
};
export default (
export default () => (
<I18nextProvider i18n={i18n}>
<Error401 />
</I18nextProvider>

View File

@ -1,4 +1,4 @@
import moment from "moment";
import moment from "moment-timezone";
import { LANGUAGE } from "@docspace/common/constants";
import { getCookie } from "@docspace/components/utils/cookie";
@ -6,7 +6,7 @@ import { getCookie } from "@docspace/components/utils/cookie";
export const getRelativeDateDay = (t, date) => {
moment.locale(getCookie(LANGUAGE));
const given = moment(date);
const given = moment(date).tz(window.timezone || "");
const now = moment();
const weekAgo = moment().subtract(1, "week");

View File

@ -19,7 +19,7 @@ import LockedReactSvgUrl from "PUBLIC_DIR/images/locked.react.svg?url";
import LoadedReactSvgUrl from "PUBLIC_DIR/images/loaded.react.svg?url";
import TrashReactSvgUrl from "PUBLIC_DIR/images/trash.react.svg?url";
import ClockReactSvg from "PUBLIC_DIR/images/clock.react.svg";
import moment from "moment";
import moment from "moment-timezone";
import { RoomsType } from "@docspace/common/constants";
import { StyledLinkRow } from "./StyledPublicRoom";
@ -56,7 +56,9 @@ const LinkRow = (props) => {
const isLocked = !!password;
const expiryDate = !!expirationDate;
const date = moment(expirationDate).format("LLL");
const date = moment(expirationDate)
.tz(window.timezone || "")
.format("LLL");
const tooltipContent = isExpired
? t("Translations:LinkHasExpiredAndHasBeenDisabled")
@ -235,7 +237,7 @@ const LinkRow = (props) => {
size={16}
iconName={CopyReactSvgUrl}
onClick={onCopyExternalLink}
title={t("Files:CopyGeneralLink")}
title={primary ? t("Files:CopyGeneralLink") : t("Files:CopyLink")}
/>
</>
)}

View File

@ -258,33 +258,20 @@ const StyledSimpleFilesRow = styled(Row)`
`}
}
@media ${tablet} {
.badges {
flex-direction: row-reverse;
gap: 24px;
}
.badges {
flex-direction: row-reverse;
gap: 24px;
}
.file__badges,
.room__badges,
.folder__badges {
> div {
margin-left: 0;
margin-right: 0;
}
}
.file__badges,
.room__badges,
.folder__badges {
margin-top: 0px;
.file__badges,
.room__badges,
.folder__badges {
> div {
margin-top: 0px;
}
}
.file__badges,
.folder__badges,
.room__badges {
> div {
margin-top: 0px;
margin-left: 0;
margin-right: 0;
}
}
@ -443,7 +430,7 @@ const SimpleFilesRow = (props) => {
mode={"modern"}
sectionWidth={sectionWidth}
contentElement={
isSmallContainer || isRooms ? null : quickButtonsComponent
isMobileDevice || isRooms ? null : quickButtonsComponent
}
badgesComponent={!isMobileDevice && badgesComponent}
onSelect={onContentFileSelect}
@ -476,7 +463,7 @@ const SimpleFilesRow = (props) => {
sectionWidth={sectionWidth}
onFilesClick={onFilesClick}
quickButtons={
isSmallContainer || isRooms ? quickButtonsComponent : null
isMobileDevice || isRooms ? quickButtonsComponent : null
}
isRooms={isRooms}
badgesComponent={isMobileDevice && badgesComponent}

View File

@ -23,6 +23,8 @@ class FilesTableHeader extends React.Component {
columnStorageName,
columnInfoPanelStorageName,
isPublicRoom,
isFrame,
frameTableColumns,
} = this.props;
const defaultColumns = [];
@ -232,13 +234,25 @@ class FilesTableHeader extends React.Component {
defaultColumns.push(...columns);
}
const columns = getColumns(defaultColumns);
let columns = getColumns(defaultColumns);
const storageColumns = localStorage.getItem(this.props.tableStorageName);
const splitColumns = storageColumns && storageColumns.split(",");
const resetColumnsSize =
(splitColumns && splitColumns.length !== columns.length) || !splitColumns;
(splitColumns && splitColumns.length !== columns.length) ||
!splitColumns ||
isFrame;
const tableColumns = columns.map((c) => c.enable && c.key);
if (isFrame && frameTableColumns) {
const frameTableArray = frameTableColumns.split(",");
columns = columns.map((col) => {
col.enable = frameTableArray.includes(col.key) ? true : false;
return col;
});
}
this.setTableColumns(tableColumns);
if (fromUpdate) {
this.setState({
@ -407,6 +421,7 @@ class FilesTableHeader extends React.Component {
withPaging,
tagRef,
setHideColumns,
isFrame,
} = this.props;
const {
@ -437,6 +452,7 @@ class FilesTableHeader extends React.Component {
tagRef={tagRef}
setHideColumns={setHideColumns}
settingsTitle={t("Files:TableSettingsTitle")}
showSettings={!isFrame}
/>
);
}
@ -470,7 +486,7 @@ export default inject(
const isRooms = isRoomsFolder || isArchiveFolder;
const withContent = canShare;
const sortingVisible = !isRecentFolder;
const { withPaging } = auth.settingsStore;
const { withPaging, isFrame, frameConfig } = auth.settingsStore;
const {
tableStorageName,
@ -553,6 +569,9 @@ export default inject(
isTrashFolder,
isPublicRoom,
publicRoomKey,
isFrame,
frameTableColumns: frameConfig?.viewTableColumns,
};
}
)(

View File

@ -28,6 +28,8 @@ import PersonUserReactSvgUrl from "PUBLIC_DIR/images/person.user.react.svg?url";
import InviteAgainReactSvgUrl from "PUBLIC_DIR/images/invite.again.react.svg?url";
import PublicRoomIconUrl from "PUBLIC_DIR/images/public-room.react.svg?url";
import PluginMoreReactSvgUrl from "PUBLIC_DIR/images/plugin.more.react.svg?url";
import LeaveRoomSvgUrl from "PUBLIC_DIR/images/logout.react.svg?url";
import CatalogRoomsReactSvgUrl from "PUBLIC_DIR/images/catalog.rooms.react.svg?url";
import React from "react";
import { inject, observer } from "mobx-react";
@ -226,6 +228,9 @@ const SectionHeaderContent = (props) => {
currentDeviceType,
isFrame,
onClickArchive,
setLeaveRoomDialogVisible,
inRoom,
onClickCreateRoom,
} = props;
const navigate = useNavigate();
@ -484,6 +489,10 @@ const SectionHeaderContent = (props) => {
onClickArchive(e);
};
const onLeaveRoom = () => {
setLeaveRoomDialogVisible(true);
};
const renameAction = () => {
const event = new Event(Events.RENAME);
@ -761,12 +770,28 @@ const SectionHeaderContent = (props) => {
"data-action": "archive",
action: "archive",
},
{
id: "option_create-room",
label: t("Files:CreateRoom"),
key: "create-room",
icon: CatalogRoomsReactSvgUrl,
onClick: onClickCreateRoom,
disabled: isArchiveFolder || !inRoom || isPublicRoom,
},
{
id: "option_leave-room",
key: "leave-room",
label: t("LeaveTheRoom"),
icon: LeaveRoomSvgUrl,
onClick: onLeaveRoom,
disabled: isArchiveFolder || !inRoom || isPublicRoom,
},
{
id: "header_option_download",
key: "download",
label: t("Common:Download"),
onClick: onDownloadAction,
disabled: !isRoom || !security?.Download,
disabled: !security?.Download,
icon: DownloadReactSvgUrl,
},
{
@ -1157,6 +1182,7 @@ export default inject(
setInvitePanelOptions,
setInviteUsersWarningDialogVisible,
setRoomSharingPanelVisible,
setLeaveRoomDialogVisible,
} = dialogsStore;
const {
@ -1177,13 +1203,14 @@ export default inject(
onClickBack,
emptyTrashInProgress,
moveToPublicRoom,
onClickCreateRoom
} = filesActionsStore;
const { oformsFilter } = oformsStore;
const { setIsVisible, isVisible } = auth.infoPanelStore;
const { title, id, roomType, pathParts, navigationPath, security } =
const { title, id, roomType, pathParts, navigationPath, security, inRoom } =
selectedFolderStore;
const selectedFolder = { ...selectedFolderStore };
@ -1320,6 +1347,7 @@ export default inject(
selectedFolder,
onClickEditRoom,
onClickCreateRoom,
onClickInviteUsers,
onShowInfoPanel,
onClickArchive,
@ -1362,6 +1390,8 @@ export default inject(
setRoomSharingPanelVisible,
isFrame,
currentDeviceType,
setLeaveRoomDialogVisible,
inRoom,
};
}
)(

View File

@ -301,13 +301,13 @@ const LanguageAndTimeZone = (props) => {
setState((val) => ({ ...val, isLoading: true }));
setLanguageAndTime(language.key, timezone.key)
.then(
() =>
!user.cultureName &&
.then(() => {
!user.cultureName &&
setCookie(LANGUAGE, language.key || "en", {
"max-age": COOKIE_EXPIRATION_YEAR,
})
)
});
window.timezone = timezone.key;
})
.then(() => toastr.success(t("SuccessfullySaveSettingsMessage")))
.then(
() => !user.cultureName && lng !== language.key && location.reload()

View File

@ -70,6 +70,7 @@ const WelcomePageSettings = (props) => {
greetingTitleDefaultFromSessionStorage = getFromSessionStorage(
"greetingTitleDefault"
);
getGreetingSettingsIsDefault();
setDocumentTitle(t("CustomTitlesWelcome"));
@ -193,8 +194,10 @@ const WelcomePageSettings = (props) => {
toastr.success(t("SuccessfullySaveGreetingSettingsMessage"));
})
.catch((error) => toastr.error(error))
.finally(() =>
setState((val) => ({ ...val, isLoadingGreetingSave: false }))
.finally(() => {
getGreetingSettingsIsDefault();
setState((val) => ({ ...val, isLoadingGreetingSave: false }));
}
);
setState((val) => ({ ...val, showReminder: false }));
@ -206,9 +209,10 @@ const WelcomePageSettings = (props) => {
const onRestoreGreetingSettings = () => {
setState((val) => ({ ...val, isLoadingGreetingRestore: true }));
restoreGreetingTitle()
.then(() => {
.then((defaultTitle) => {
setState((val) => ({
...val,
greetingTitle: defaultTitle,
showReminder: false,
}));
@ -218,8 +222,10 @@ const WelcomePageSettings = (props) => {
toastr.success(t("SuccessfullySaveGreetingSettingsMessage"));
})
.catch((error) => toastr.error(error))
.finally(() =>
setState((val) => ({ ...val, isLoadingGreetingRestore: false }))
.finally(() => {
getGreetingSettingsIsDefault();
setState((val) => ({ ...val, isLoadingGreetingRestore: false }));
}
);
};

View File

@ -284,7 +284,6 @@ const PortalIntegration = (props) => {
);
const [config, setConfig] = useState({
hash: `${API_JS_HASH}`,
width: `${width}${widthDimension.label}`,
height: `${height}${heightDimension.label}`,
frameId: "ds-frame",

View File

@ -84,7 +84,7 @@ const CSP = ({ t, cspDomains, getCSPSettings, setCSPSettings }) => {
const deleteDomain = (value) => {
const domains = cspDomains.filter((item) => item !== value);
setCSPSettings({ domains });
setCSPSettings({ domains, setDefaultIfEmpty: true });
};
const addDomain = () => {

View File

@ -1,5 +1,5 @@
import React from "react";
import moment from "moment";
import moment from "moment-timezone";
import styled from "styled-components";
import Text from "@docspace/components/text";
@ -46,7 +46,13 @@ const BarItem = styled.div`
`;
const BarItemHeader = ({ children }) => (
<Text as="h3" color="#A3A9AE" fontSize="12px" fontWeight={600} className="barItemHeader">
<Text
as="h3"
color="#A3A9AE"
fontSize="12px"
fontWeight={600}
className="barItemHeader"
>
{children}
</Text>
);
@ -61,7 +67,12 @@ const DetailsBar = ({ eventDetails }) => {
const formatDate = (date) => {
return (
moment(date).locale(i18n.language).format("MMM D, YYYY, h:mm:ss A") + " " + t("Common:UTC")
moment(date)
.locale(i18n.language)
.tz(window.timezone || "")
.format("MMM D, YYYY, h:mm:ss A") +
" " +
t("Common:UTC")
);
};

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect, useTransition, Suspense } from "react";
import moment from "moment";
import moment from "moment-timezone";
import styled from "styled-components";
import HistoryFilterHeader from "./sub-components/HistoryFilterHeader";
@ -23,9 +23,15 @@ const parseUrl = (url) => {
params[key] = value;
}
params.deliveryDate =
params.deliveryDate === "null" ? null : moment(params.deliveryDate, "YYYY-MM-DD");
params.deliveryFrom = moment(params.deliveryFrom, "HH:mm");
params.deliveryTo = moment(params.deliveryTo, "HH:mm");
params.deliveryDate === "null"
? null
: moment(params.deliveryDate, "YYYY-MM-DD").tz(window.timezone || "");
params.deliveryFrom = moment(params.deliveryFrom, "HH:mm").tz(
window.timezone || ""
);
params.deliveryTo = moment(params.deliveryTo, "HH:mm").tz(
window.timezone || ""
);
params.status = JSON.parse(params.status);
return params;

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect, useRef } from "react";
import styled from "styled-components";
import moment from "moment";
import moment from "moment-timezone";
import Text from "@docspace/components/text";
import { useTranslation } from "react-i18next";
@ -71,8 +71,12 @@ const DeliveryDatePicker = ({
setFilters((prevFilters) => ({
...prevFilters,
deliveryDate: null,
deliveryFrom: moment().startOf("day"),
deliveryTo: moment().endOf("day"),
deliveryFrom: moment()
.tz(window.timezone || "")
.startOf("day"),
deliveryTo: moment()
.tz(window.timezone || "")
.endOf("day"),
}));
setIsTimeOpen(false);
setIsCalendarOpen(false);
@ -91,8 +95,12 @@ const DeliveryDatePicker = ({
setFilters((prevFilters) => ({
...prevFilters,
deliveryDate: date,
deliveryFrom: moment().startOf("day"),
deliveryTo: moment().endOf("day"),
deliveryFrom: moment()
.tz(window.timezone || "")
.startOf("day"),
deliveryTo: moment()
.tz(window.timezone || "")
.endOf("day"),
}));
};
@ -121,9 +129,9 @@ const DeliveryDatePicker = ({
const SelectedDateTime = () => {
const formattedTime = isTimeEqual
? ""
: ` ${filters.deliveryFrom.format("HH:mm")} - ${moment(
filters.deliveryTo
).format("HH:mm")}`;
: ` ${filters.deliveryFrom.format("HH:mm")} - ${moment(filters.deliveryTo)
.tz(window.timezone || "")
.format("HH:mm")}`;
return (
<div>
@ -192,7 +200,8 @@ const DeliveryDatePicker = ({
isInline
fontWeight={600}
color="#A3A9AE"
className="mr-8">
className="mr-8"
>
{t("From")}
</Text>
<TimePicker

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect } from "react";
import { inject, observer } from "mobx-react";
import moment from "moment";
import moment from "moment-timezone";
import ModalDialog from "@docspace/components/modal-dialog";
import styled, { css } from "styled-components";
@ -54,7 +54,10 @@ Separator.defaultProps = { theme: Base };
const constructUrl = (baseUrl, filters) => {
const url = new URL(baseUrl, "http://127.0.0.1:8092/");
url.searchParams.append("deliveryDate", filters.deliveryDate?.format("YYYY-MM-DD") || null);
url.searchParams.append(
"deliveryDate",
filters.deliveryDate?.format("YYYY-MM-DD") || null
);
url.searchParams.append("deliveryFrom", filters.deliveryFrom.format("HH:mm"));
url.searchParams.append("deliveryTo", filters.deliveryTo.format("HH:mm"));
url.searchParams.append("status", JSON.stringify(filters.status));
@ -63,20 +66,33 @@ const constructUrl = (baseUrl, filters) => {
};
function areArraysEqual(array1, array2) {
return array1.length === array2.length && array1.every((val, index) => val === array2[index]);
return (
array1.length === array2.length &&
array1.every((val, index) => val === array2[index])
);
}
const FilterDialog = (props) => {
const { visible, closeModal, applyFilters, formatFilters, setHistoryFilters, historyFilters } =
props;
const {
visible,
closeModal,
applyFilters,
formatFilters,
setHistoryFilters,
historyFilters,
} = props;
const { t } = useTranslation(["Webhooks", "Files", "Common"]);
const { id } = useParams();
const navigate = useNavigate();
const [filters, setFilters] = useState({
deliveryDate: null,
deliveryFrom: moment().startOf("day"),
deliveryTo: moment().endOf("day"),
deliveryFrom: moment()
.tz(window.timezone || "")
.startOf("day"),
deliveryTo: moment()
.tz(window.timezone || "")
.endOf("day"),
status: [],
});
@ -101,8 +117,12 @@ const FilterDialog = (props) => {
if (filters.deliveryDate !== null || filters.status.length > 0) {
setFilters({
deliveryDate: null,
deliveryFrom: moment().startOf("day"),
deliveryTo: moment().endOf("day"),
deliveryFrom: moment()
.tz(window.timezone || "")
.startOf("day"),
deliveryTo: moment()
.tz(window.timezone || "")
.endOf("day"),
status: [],
});
}
@ -110,7 +130,12 @@ const FilterDialog = (props) => {
} else {
setFilters(historyFilters);
setIsApplied(true);
navigate(constructUrl(`/portal-settings/developer-tools/webhooks/${id}`, historyFilters));
navigate(
constructUrl(
`/portal-settings/developer-tools/webhooks/${id}`,
historyFilters
)
);
}
setIsLoaded(true);
}, [historyFilters, visible]);
@ -124,7 +149,12 @@ const FilterDialog = (props) => {
: filters.deliveryDate === null && filters.status.length === 0;
return (
<ModalDialogContainer withFooterBorder visible={visible} onClose={closeModal} displayType="aside">
<ModalDialogContainer
withFooterBorder
visible={visible}
onClose={closeModal}
displayType="aside"
>
<ModalDialog.Header>{t("Files:Filter")}</ModalDialog.Header>
<ModalDialog.Body>
<DialogBodyWrapper>

View File

@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import moment from "moment";
import moment from "moment-timezone";
import styled from "styled-components";
import { inject, observer } from "mobx-react";
@ -42,11 +42,17 @@ const StatusBar = (props) => {
return (
<SelectedItem
label={
moment(historyFilters.deliveryDate).format("DD MMM YYYY") +
moment(historyFilters.deliveryDate)
.format("DD MMM YYYY")
.tz(window.timezone || "") +
" " +
moment(historyFilters.deliveryFrom).format("HH:mm") +
moment(historyFilters.deliveryFrom)
.format("HH:mm")
.tz(window.timezone || "") +
" - " +
moment(historyFilters.deliveryTo).format("HH:mm")
moment(historyFilters.deliveryTo)
.format("HH:mm")
.tz(window.timezone || "")
}
onClose={clearDate}
onClick={clearDate}

View File

@ -1,5 +1,5 @@
import React from "react";
import moment from "moment";
import moment from "moment-timezone";
import styled from "styled-components";
import Text from "@docspace/components/text";
@ -33,6 +33,7 @@ export const HistoryRowContent = ({ sectionWidth, historyItem }) => {
const formattedDelivery =
moment(historyItem.delivery)
.tz(window.timezone || "")
.locale(i18n.language)
.format("MMM D, YYYY, h:mm:ss A") +
" " +

View File

@ -1,5 +1,5 @@
import React from "react";
import moment from "moment";
import moment from "moment-timezone";
import styled, { css } from "styled-components";
import { inject, observer } from "mobx-react";
@ -65,7 +65,8 @@ const HistoryTableRow = (props) => {
const navigate = useNavigate();
const { id } = useParams();
const redirectToDetails = () => navigate(window.location.pathname + `/${item.id}`);
const redirectToDetails = () =>
navigate(window.location.pathname + `/${item.id}`);
const handleRetryEvent = async () => {
if (isRetryPending) {
return;
@ -97,7 +98,10 @@ const HistoryTableRow = (props) => {
];
const formattedDelivery =
moment(item.delivery).locale(i18n.language).format("MMM D, YYYY, h:mm:ss A") +
moment(item.delivery)
.tz(window.timezone || "")
.locale(i18n.language)
.format("MMM D, YYYY, h:mm:ss A") +
" " +
t("Common:UTC");
@ -121,11 +125,22 @@ const HistoryTableRow = (props) => {
const isChecked = isIdChecked(item.id);
return (
<StyledWrapper className={isChecked ? "selected-table-row" : ""} onClick={onRowClick}>
<StyledTableRow contextOptions={contextOptions} checked={isChecked} hideColumns={hideColumns}>
<StyledWrapper
className={isChecked ? "selected-table-row" : ""}
onClick={onRowClick}
>
<StyledTableRow
contextOptions={contextOptions}
checked={isChecked}
hideColumns={hideColumns}
>
<TableCell>
<TableCell checked={isChecked} className="checkboxWrapper">
<Checkbox className="checkbox" onChange={onCheckboxClick} isChecked={isChecked} />
<Checkbox
className="checkbox"
onChange={onCheckboxClick}
isChecked={isChecked}
/>
</TableCell>
<Text fontWeight={600}>{item.id}</Text>

View File

@ -82,7 +82,7 @@ const PluginPage = ({
export default inject(({ auth, pluginStore }) => {
const { pluginOptions, currentColorScheme, theme } = auth.settingsStore;
const withUpload = pluginOptions.includes("upload");
const withUpload = pluginOptions.upload;
const {
pluginList,

View File

@ -28,7 +28,7 @@ import {
TableDataCell,
} from "./styled-active-sessions";
import { DeviceType } from "@docspace/common/constants";
import moment from "moment";
import moment from "moment-timezone";
const removeIcon = (
<ReactSVG className="remove-icon" src={RemoveSessionSvgUrl} />
@ -114,7 +114,10 @@ const ActiveSessions = ({
};
const convertTime = (date) => {
return moment(date).locale(locale).format("L, LTS");
return moment(date)
.tz(window.timezone || "")
.locale(locale)
.format("L, LTS");
};
const tableCell = (platform, browser) =>
interfaceDirection === "rtl" && !isMobile ? (

View File

@ -12,6 +12,7 @@ import {
createPasswordHash,
frameCallCommand,
} from "@docspace/common/utils";
import { RoomsType } from "@docspace/common/constants";
const Sdk = ({
frameConfig,
@ -25,6 +26,8 @@ const Sdk = ({
getSettings,
user,
updateProfileCulture,
getRoomsIcon,
getPrimaryLink,
}) => {
useEffect(() => {
window.addEventListener("message", handleMessage, false);
@ -118,8 +121,18 @@ const Sdk = ({
};
const onSelectRoom = useCallback(
(data) => {
data[0].icon = toRelativeUrl(data[0].icon);
async (data) => {
if (data[0].logo.large !== "") {
data[0].icon = toRelativeUrl(data[0].logo.large);
} else {
data[0].icon = await getRoomsIcon(data[0].roomType, false, 32);
}
if (data[0].roomType === RoomsType.PublicRoom) {
const { sharedTo } = await getPrimaryLink(data[0].id);
data[0].requestToken = sharedTo?.requestToken;
}
frameCallEvent({ event: "onSelectCallback", data });
},
[frameCallEvent]
@ -150,8 +163,8 @@ const Sdk = ({
case "room-selector":
component = (
<RoomSelector
withCancelButton={true}
withHeader={false}
withCancelButton={frameConfig?.showSelectorCancel}
withHeader={frameConfig?.showSelectorHeader}
onAccept={onSelectRoom}
onCancel={onClose}
/>
@ -162,11 +175,14 @@ const Sdk = ({
<FilesSelector
isPanelVisible={true}
embedded={true}
withHeader={false}
withHeader={frameConfig?.showSelectorHeader}
isSelect={true}
onSelectFile={onSelectFile}
onClose={onClose}
filterParam={"ALL"}
isUserOnly={selectorType === "userFolderOnly"}
isRoomsOnly={selectorType === "roomsOnly"}
withCancelButton={frameConfig?.showSelectorCancel}
/>
);
break;
@ -177,13 +193,14 @@ const Sdk = ({
return component;
};
export default inject(({ auth, settingsStore, peopleStore }) => {
export default inject(({ auth, settingsStore, peopleStore, filesStore }) => {
const { login, logout, userStore } = auth;
const { theme, setFrameConfig, frameConfig, getSettings, isLoaded } =
auth.settingsStore;
const { loadCurrentUser, user } = userStore;
const { updateProfileCulture } = peopleStore.targetUserStore;
const { getIcon } = settingsStore;
const { getIcon, getRoomsIcon } = settingsStore;
const { getPrimaryLink } = filesStore;
return {
theme,
@ -194,8 +211,10 @@ export default inject(({ auth, settingsStore, peopleStore }) => {
getSettings,
loadCurrentUser,
getIcon,
getRoomsIcon,
isLoaded,
updateProfileCulture,
user,
getPrimaryLink,
};
})(observer(Sdk));

View File

@ -13,6 +13,8 @@ const StyledBody = styled.div`
}
.loader-history-rows {
padding-top: 12px;
${({ theme }) =>
theme.interfaceDirection === "rtl"
? `padding-left: 16px;`

View File

@ -19,7 +19,8 @@ import toastr from "@docspace/components/toast/toastr";
import { Encoder } from "@docspace/common/utils/encoder";
import { Base } from "@docspace/components/themes";
import { MAX_FILE_COMMENT_LENGTH } from "@docspace/common/constants";
import moment from "moment";
import moment from "moment-timezone";
import getCorrectDate from "@docspace/components/utils/getCorrectDate";
const StyledExternalLinkIcon = styled(ExternalLinkIcon)`
${commonIconsStyles}
@ -66,9 +67,7 @@ const VersionRow = (props) => {
}
}, [info.comment]);
const versionDate = `${moment(info.updated)
.locale(culture)
.format("L, LTS")}`;
const versionDate = getCorrectDate(culture, info.updated, "L", "LTS");
const title = `${Encoder.htmlDecode(info.updatedBy?.displayName)}`;

View File

@ -91,6 +91,12 @@ class AccessRightsStore {
(userIsVisitor || userIsCollaborator)
);
};
canMakePowerUser = (user) => {
const { isVisitor: userIsVisitor, isCollaborator: userIsCollaborator } =
user;
return userIsVisitor || userIsCollaborator;
};
canActivateUser = (user) => {
const { id, isOwner, isAdmin } = this.authStore.userStore.user;

View File

@ -430,9 +430,12 @@ class ContextOptionsStore {
this.dialogsStore.setDownloadDialogVisible(true);
};
onClickCreateRoom = () => {
onClickCreateRoom = (item) => {
this.filesActionsStore.setProcessCreatingRoomFromData(true);
const event = new Event(Events.ROOM_CREATE);
if (item && item.isFolder) {
event.title = item.title;
}
window.dispatchEvent(event);
};
@ -1355,7 +1358,7 @@ class ContextOptionsStore {
key: "create-room",
label: t("Files:CreateRoom"),
icon: CatalogRoomsReactSvgUrl,
onClick: this.onClickCreateRoom,
onClick: () => this.onClickCreateRoom(item),
disabled: this.selectedFolderStore.rootFolderType !== FolderType.USER,
},
{

View File

@ -175,27 +175,11 @@ class PeopleStore {
setIsVisible(true);
};
getHeaderMenu = (t) => {
const {
hasUsersToMakeEmployees,
hasUsersToActivate,
hasUsersToDisable,
hasUsersToInvite,
hasUsersToRemove,
hasOnlyOneUserToRemove,
hasFreeUsers,
userSelectionRole,
selection,
} = this.selectionStore;
const { setSendInviteDialogVisible, setDeleteProfileDialogVisible } =
this.dialogStore;
const { toggleDeleteProfileEverDialog } = this.contextOptionsStore;
getUsersRightsSubmenu = (t) => {
const { userSelectionRole, selectionUsersRights } = this.selectionStore;
const { isOwner } = this.authStore.userStore.user;
const { isVisible } = this.authStore.infoPanelStore;
const options = [];
const adminOption = {
@ -218,22 +202,71 @@ class PeopleStore {
key: "manager",
isActive: userSelectionRole === "manager",
};
const userOption = {
id: "menu_change-user_user",
className: "group-menu_drop-down",
label: t("Common:User"),
title: t("Common:User"),
// const userOption = {
// id: "menu_change-user_user",
// className: "group-menu_drop-down",
// label: t("Common:User"),
// title: t("Common:User"),
// onClick: (e) => this.onChangeType(e),
// "data-action": "user",
// key: "user",
// isActive: userSelectionRole === "user",
// };
const collaboratorOption = {
id: "menu_change-collaborator",
key: "collaborator",
title: t("Common:PowerUser"),
label: t("Common:PowerUser"),
"data-action": "collaborator",
onClick: (e) => this.onChangeType(e),
"data-action": "user",
key: "user",
isActive: userSelectionRole === "user",
isActive: userSelectionRole === "collaborator",
};
isOwner && options.push(adminOption);
const { isVisitor, isCollaborator, isRoomAdmin, isAdmin } =
selectionUsersRights;
options.push(managerOption);
if (isVisitor > 0) {
isOwner && options.push(adminOption);
options.push(managerOption);
options.push(collaboratorOption);
hasFreeUsers && options.push(userOption);
return options;
}
if (isCollaborator > 0 || (isRoomAdmin > 0 && isAdmin > 0)) {
isOwner && options.push(adminOption);
options.push(managerOption);
return options;
}
if (isRoomAdmin > 0) {
isOwner && options.push(adminOption);
return options;
}
if (isAdmin > 0) {
options.push(managerOption);
return options;
}
};
getHeaderMenu = (t) => {
const {
hasUsersToMakeEmployees,
hasUsersToActivate,
hasUsersToDisable,
hasUsersToInvite,
hasUsersToRemove,
selection,
} = this.selectionStore;
const { setSendInviteDialogVisible } = this.dialogStore;
const { toggleDeleteProfileEverDialog } = this.contextOptionsStore;
const { isVisible } = this.authStore.infoPanelStore;
const headerMenu = [
{
@ -243,7 +276,7 @@ class PeopleStore {
disabled: !hasUsersToMakeEmployees,
iconUrl: ChangeToEmployeeReactSvgUrl,
withDropDown: true,
options: options,
options: this.getUsersRightsSubmenu(t),
},
{
id: "menu-info",

View File

@ -5,6 +5,12 @@ import { getUserStatus } from "../helpers/people-helpers";
class SelectionStore {
peopleStore = null;
selection = [];
selectionUsersRights = {
isVisitor: 0,
isCollaborator: 0,
isRoomAdmin: 0,
isAdmin: 0,
};
bufferSelection = null;
selected = "none";
@ -20,9 +26,33 @@ class SelectionStore {
});
};
resetUsersRight = () => {
for (const key in this.selectionUsersRights) {
this.selectionUsersRights[key] = 0;
}
};
incrementUsersRights = (selection) => {
for (const key in this.selectionUsersRights) {
if (selection[key]) {
this.selectionUsersRights[key]++;
}
}
};
decrementUsersRights = (selection) => {
for (const key in this.selectionUsersRights) {
if (selection[key]) {
this.selectionUsersRights[key]--;
}
}
};
setSelection = (selection) => {
//console.log("setSelection", { selection });
// console.log("setSelection", { selection });
this.selection = selection;
selection.length === 0 && this.resetUsersRight();
};
setSelections = (added, removed, clear = false) => {
@ -45,10 +75,14 @@ class SelectionStore {
const isFound = this.selection.findIndex((f) => f.id == id) === -1;
isFound &&
newSelections.push(
this.peopleStore.usersStore.peopleList.find((f) => f.id == id)
if (isFound) {
const user = this.peopleStore.usersStore.peopleList.find(
(f) => f.id == id
);
newSelections.push(user);
this.incrementUsersRights(user);
}
}
for (let item of removed) {
@ -61,7 +95,12 @@ class SelectionStore {
const splitValue = value && value.split("_");
const id = splitValue.slice(1, -3).join("_");
newSelections = newSelections.filter((f) => !(f.id == id));
const index = newSelections.findIndex((item) => item.id == id);
if (index !== -1) {
this.decrementUsersRights(newSelections[index]);
newSelections.splice(index, 1);
}
}
this.setSelection(newSelections);
@ -80,11 +119,13 @@ class SelectionStore {
const exists = index > -1;
//console.log("selectUser", { user, selection: this.selection, exists });
// console.log("selectUser", { user, selection: this.selection, exists });
if (exists) return;
this.setSelection([...this.selection, user]);
this.incrementUsersRights(user);
};
deselectUser = (user) => {
@ -100,6 +141,8 @@ class SelectionStore {
newData.splice(index, 1);
this.decrementUsersRights(this.selection[index]);
this.setSelection(newData);
};
@ -170,7 +213,12 @@ class SelectionStore {
return users.length > 0;
}
get hasUsersToMakePowerUser() {
const { canMakePowerUser } = this.peopleStore.accessRightsStore;
const users = this.selection.filter((x) => canMakePowerUser(x));
return users.length > 0;
}
get getUsersToMakeEmployees() {
const { canMakeEmployeeUser } = this.peopleStore.accessRightsStore;

View File

@ -25,6 +25,10 @@ import {
import { combineUrl } from "@docspace/common/utils";
import config from "PACKAGE_FILE";
import { getUnexpectedErrorText } from "SRC_DIR/helpers/filesUtils";
import {
getCategoryTypeByFolderType,
getCategoryUrl,
} from "SRC_DIR/helpers/utils";
const UPLOAD_LIMIT_AT_ONCE = 5;
@ -1527,6 +1531,26 @@ class UploadDataStore {
return operationItem;
};
navigateToNewFolderLocation = async (folderId) => {
const { filter } = this.filesStore;
filter.folder = folderId;
try {
const { rootFolderType, parentId } = await getFolderInfo(folderId);
const path = getCategoryUrl(
getCategoryTypeByFolderType(rootFolderType, parentId),
folderId
);
window.DocSpace.navigate(`${path}?${filter.toUrlParams()}`, {
replace: true,
});
} catch (e) {
console.log(e);
}
};
moveToCopyTo = (destFolderId, pbData, isCopy, fileIds, folderIds) => {
const {
fetchFiles,
@ -1539,6 +1563,7 @@ class UploadDataStore {
const { clearSecondaryProgressData, setSecondaryProgressBarData, label } =
this.secondaryProgressDataStore;
const { withPaging } = this.authStore.settingsStore;
const isMovingCurrentFolder = !isCopy && this.dialogsStore.isFolderActions;
let receivedFolder = destFolderId;
let updatedFolder = this.selectedFolderStore.id;
@ -1558,6 +1583,8 @@ class UploadDataStore {
() => clearSecondaryProgressData(pbData.operationId),
TIMEOUT
);
isMovingCurrentFolder &&
this.navigateToNewFolderLocation(this.selectedFolderStore.id);
this.dialogsStore.setIsFolderActions(false);
return;
}
@ -1578,6 +1605,8 @@ class UploadDataStore {
() => clearSecondaryProgressData(pbData.operationId),
TIMEOUT
);
isMovingCurrentFolder &&
this.navigateToNewFolderLocation(this.selectedFolderStore.id);
this.dialogsStore.setIsFolderActions(false);
});
} else {

View File

@ -384,7 +384,6 @@ module.exports = (env, argv) => {
return JSON.stringify(today.toISOString().split(".")[0] + "Z");
}, true),
IS_PERSONAL: env.personal || false,
API_JS_HASH: JSON.stringify(runtime.checksums["api.js"] || dateHash),
};
config.plugins.push(new DefinePlugin(defines));

View File

@ -3,8 +3,8 @@ import React from "react";
import Avatar from "@docspace/components/avatar";
import Text from "@docspace/components/text";
import Checkbox from "@docspace/components/checkbox";
import Loader from "@docspace/components/loader";
import Loaders from "@docspace/common/components/Loaders";
import Loaders from "../../Loaders";
const Option = ({
style,
isMultiSelect,

View File

@ -3,7 +3,7 @@ import { inject, observer } from "mobx-react";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { combineUrl } from "@docspace/common/utils";
import { combineUrl } from "../../../utils";
import AlertComponent from "../../AlertComponent";
import RectangleSkeleton from "@docspace/components/skeletons/rectangle";

View File

@ -1,7 +1,7 @@
import React from "react";
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";
import Loaders from "@docspace/common/components/Loaders";
import Loaders from "../../Loaders";
import { Link } from "react-router-dom";

View File

@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import Zendesk, { ZendeskAPI } from "@docspace/common/components/Zendesk";
import Zendesk, { ZendeskAPI } from "../../Zendesk";
import { LIVE_CHAT_LOCAL_STORAGE_KEY } from "../../../constants";
import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";

View File

@ -3,7 +3,7 @@ import { inject, observer } from "mobx-react";
import { useNavigate } from "react-router-dom";
import { useTranslation, Trans } from "react-i18next";
import { combineUrl } from "@docspace/common/utils";
import { combineUrl } from "../../../utils";
import AlertComponent from "../../AlertComponent";
import RectangleSkeleton from "@docspace/components/skeletons/rectangle";

View File

@ -7,7 +7,7 @@ import ModalDialog from "@docspace/components/modal-dialog";
import Textarea from "@docspace/components/textarea";
import FieldContainer from "@docspace/components/field-container";
import { mobile, tablet } from "@docspace/components/utils/device";
import { sendRecoverRequest } from "@docspace/common/api/settings";
import { sendRecoverRequest } from "../../../api/settings";
import toastr from "@docspace/components/toast/toastr";
import { useTranslation } from "react-i18next";

View File

@ -14,7 +14,7 @@ import { Base } from "@docspace/components/themes";
import SortDesc from "PUBLIC_DIR/images/sort.desc.react.svg";
import SortReactSvgUrl from "PUBLIC_DIR/images/sort.react.svg?url";
import Backdrop from "@docspace/components/backdrop";
import { Events } from "@docspace/common/constants";
import { Events } from "../../../constants";
const selectedViewIcon = css`
svg {

View File

@ -1,4 +1,3 @@
import { isMobile } from "react-device-detect";
import React, {
useState,
useCallback,
@ -7,25 +6,29 @@ import React, {
useRef,
} from "react";
import ViewerWrapper from "./sub-components/ViewerWrapper";
import {
isMobile as isMobileUtils,
isTablet,
} from "@docspace/components/utils/device";
import { FileStatus } from "../../constants";
import { getFileExtension } from "../../utils";
import { checkDialogsOpen } from "../../utils/checkDialogsOpen";
import { MediaViewerProps } from "./MediaViewer.props";
import { FileStatus } from "@docspace/common/constants";
import {
isNullOrUndefined,
KeyboardEventKeys,
mapSupplied,
mediaTypes,
} from "./helpers";
import { getFileExtension } from "@docspace/common/utils";
import {
getDesktopMediaContextModel,
getMobileMediaContextModel,
getPDFContextModel,
} from "./helpers/contextModel";
import ViewerWrapper from "./sub-components/ViewerWrapper";
import { checkDialogsOpen } from "../../utils/checkDialogsOpen";
import type { MediaViewerProps } from "./MediaViewer.props";
function MediaViewer({
playlistPos,
@ -244,6 +247,8 @@ function MediaViewer({
});
}
const isMobile = isMobileUtils() || isTablet();
return isMobile
? model
: isImage && !isMobile

View File

@ -1,6 +1,6 @@
import { Dispatch, SetStateAction } from "react";
import type { Dispatch, SetStateAction } from "react";
import { getCustomToolbar } from "../../helpers/getCustomToolbar";
import { ContextMenuModel } from "../../types";
import type { ContextMenuModel, DevicesType } from "../../types";
interface ImageViewerProps {
src?: string;
@ -14,6 +14,7 @@ interface ImageViewerProps {
panelVisible: boolean;
mobileDetails: JSX.Element;
toolbar: ReturnType<typeof getCustomToolbar>;
devices: DevicesType;
onPrev: VoidFunction;
onNext: VoidFunction;

View File

@ -1,5 +1,5 @@
import { useGesture } from "@use-gesture/react";
import { isMobile, isDesktop } from "react-device-detect";
import { isDesktop as isDesktopDeviceDetect } from "react-device-detect";
import { useSpring, config } from "@react-spring/web";
import React, { SyntheticEvent, useEffect, useRef, useState } from "react";
@ -55,6 +55,7 @@ function ImageViewer({
isTiff,
contextModel,
errorTitle,
devices,
}: ImageViewerProps) {
const imgRef = useRef<HTMLImageElement>(null);
const imgWrapperRef = useRef<HTMLDivElement>(null);
@ -84,6 +85,8 @@ function ImageViewer({
opacity: 1,
}));
const { isMobile, isDesktop } = devices;
useEffect(() => {
unmountRef.current = false;
@ -846,10 +849,15 @@ function ImageViewer({
},
onClick: ({ pinching, event }) => {
if (isDesktop && event.target === imgWrapperRef.current)
if (isDesktopDeviceDetect && event.target === imgWrapperRef.current)
return onMask();
if (!imgRef.current || !containerRef.current || pinching || isDesktop)
if (
!imgRef.current ||
!containerRef.current ||
pinching ||
isDesktopDeviceDetect
)
return;
const time = new Date().getTime();
@ -1030,7 +1038,7 @@ function ImageViewer({
</ImageWrapper>
</ImageViewerContainer>
{isDesktop && panelVisible && !isError && (
{isDesktop && !isMobile && panelVisible && !isError && (
<ImageViewerToolbar
ref={toolbarRef}
toolbar={toolbar}

View File

@ -1,5 +1,6 @@
import { Dispatch, SetStateAction } from "react";
import type { Dispatch, SetStateAction } from "react";
import { getPDFToolbar } from "./../../helpers/getCustomToolbar";
import type { DevicesType } from "../../types";
interface PDFViewerProps {
src: string;
title: string;
@ -9,6 +10,7 @@ interface PDFViewerProps {
isLastImage: boolean;
isFistImage: boolean;
devices: DevicesType;
onMask: VoidFunction;
generateContextMenu: (

View File

@ -7,9 +7,8 @@ import React, {
} from "react";
import { isDesktop, isMobile } from "react-device-detect";
import { loadScript, combineUrl } from "@docspace/common/utils";
//@ts-ignore
import { getDocumentServiceLocation } from "@docspace/common/api/files";
import { loadScript, combineUrl } from "../../../../utils";
import { getDocumentServiceLocation } from "../../../../api/files";
import PDFViewerProps, { BookMark } from "./PDFViewer.props";
import ViewerLoader from "../ViewerLoader";

View File

@ -3,6 +3,7 @@ interface PlayerMessageErrorProps {
errorTitle: string;
model: ContextMenuModel[];
onMaskClick: VoidFunction;
isMobile: boolean;
}
export default PlayerMessageErrorProps;

View File

@ -1,5 +1,4 @@
import React from "react";
import { isMobile } from "react-device-detect";
import { ReactSVG } from "react-svg";
import Text from "@docspace/components/text";
@ -11,8 +10,9 @@ import {
import { isSeparator } from "../../helpers";
function PlayerMessageError({
errorTitle,
model,
isMobile,
errorTitle,
onMaskClick,
}: PlayerMessageErrorProps) {
const items = !isMobile

View File

@ -28,12 +28,10 @@ function PlayerSpeedControl({
const timerRef = useRef<NodeJS.Timeout>();
const [currentIndexSpeed, setCurrentIndexSpeed] = useState<number>(
DefaultIndexSpeed
);
const [isOpenSpeedContextMenu, setIsOpenSpeedContextMenu] = useState<boolean>(
false
);
const [currentIndexSpeed, setCurrentIndexSpeed] =
useState<number>(DefaultIndexSpeed);
const [isOpenSpeedContextMenu, setIsOpenSpeedContextMenu] =
useState<boolean>(false);
const [speedToastVisible, setSpeedToastVisible] = useState<boolean>(false);
useEffect(() => {

View File

@ -1,6 +1,7 @@
import { isMobile } from "react-device-detect";
import styled, { css } from "styled-components";
import { tablet } from "@docspace/components/utils/device";
export const HoverProgress = styled.div`
display: none;
position: absolute;
@ -177,5 +178,7 @@ export const PlayerTimelineWrapper = styled.div`
}
}
${isMobile && mobileCss}
@media ${tablet} {
${mobileCss}
}
`;

View File

@ -1,7 +1,7 @@
import { tablet } from "@docspace/components/utils/device";
import { isMobile } from "react-device-detect";
import styled, { css } from "styled-components";
import { tablet } from "@docspace/components/utils/device";
export const PlayerVolumeControlWrapper = styled.div`
display: flex;
align-items: center;
@ -143,5 +143,7 @@ export const VolumeWrapper = styled.div`
}
}
${isMobile && mobilecss}
@media ${tablet} {
${mobilecss}
}
`;

View File

@ -32,6 +32,8 @@ interface ViewerProps {
bottom?: string
) => JSX.Element;
onSetSelectionFile: VoidFunction;
currentDeviceType?: string;
}
export default ViewerProps;

View File

@ -1,7 +1,14 @@
import ReactDOM from "react-dom";
import { isMobile } from "react-device-detect";
import React, { useRef, useState, useEffect, useCallback } from "react";
import { inject, observer } from "mobx-react";
import React, {
useRef,
useState,
useEffect,
useCallback,
useMemo,
} from "react";
import { DeviceType } from "../../../../constants";
import { StyledViewerContainer } from "../../StyledComponents";
import NextButton from "../NextButton";
@ -33,6 +40,19 @@ function Viewer(props: ViewerProps) {
const contextMenuRef = useRef<{ show: (e: any) => void }>(null);
const [isFullscreen, setIsFullScreen] = useState<boolean>(false);
const devices = useMemo(
() => ({
isMobileOnly: props.currentDeviceType === DeviceType.mobile,
isMobile:
props.currentDeviceType === DeviceType.tablet ||
props.currentDeviceType === DeviceType.mobile,
isDesktop: props.currentDeviceType === DeviceType.desktop,
}),
[props.currentDeviceType]
);
const { isMobile } = devices;
useEffect(() => {
document.body.appendChild(containerRef.current);
containerRef.current.style.direction = "ltr";
@ -61,7 +81,7 @@ function Viewer(props: ViewerProps) {
clearTimeout(timerIDRef.current);
setPanelVisible(true);
};
}, [setImageTimer, setPanelVisible]);
}, [setImageTimer, setPanelVisible, isMobile]);
const resetToolbarVisibleTimer = () => {
if (panelToolbarRef.current) return;
@ -210,6 +230,7 @@ function Viewer(props: ViewerProps) {
resetToolbarVisibleTimer={resetToolbarVisibleTimer}
contextModel={props.contextModel}
errorTitle={props.errorTitle}
devices={devices}
/>,
containerRef.current
)
@ -243,6 +264,7 @@ function Viewer(props: ViewerProps) {
removeToolbarVisibleTimer={removeToolbarVisibleTimer}
removePanelVisibleTimeout={removePanelVisibleTimeout}
restartToolbarVisibleTimer={restartToolbarVisibleTimer}
devices={devices}
/>,
containerRef.current
)
@ -262,6 +284,7 @@ function Viewer(props: ViewerProps) {
isFistImage={!isNotFirstElement}
onPrev={props.onPrevClick}
onNext={props.onNextClick}
devices={devices}
/>,
containerRef.current
)}
@ -269,4 +292,8 @@ function Viewer(props: ViewerProps) {
);
}
export default Viewer;
export default inject<any>(({ auth }) => {
const { currentDeviceType } = auth.settingsStore;
return { currentDeviceType };
})(observer(Viewer));

View File

@ -1,4 +1,4 @@
import { ContextMenuModel } from "../../types";
import type { ContextMenuModel, DevicesType } from "../../types";
interface ViewerPlayerProps {
src?: string;
@ -16,6 +16,7 @@ interface ViewerPlayerProps {
isOpenContextMenu: boolean;
mobileDetails: JSX.Element;
thumbnailSrc?: string;
devices: DevicesType;
onMask: VoidFunction;
onPrev: VoidFunction;
onNext: VoidFunction;

View File

@ -1,7 +1,8 @@
import { isMobile, isMobileOnly } from "react-device-detect";
import styled, { css } from "styled-components";
import styled from "styled-components";
import { animated } from "@react-spring/web";
import { tablet, mobile } from "@docspace/components/utils/device";
export const ContainerPlayer = styled.div<{ $isFullScreen: boolean }>`
position: fixed;
inset: 0;
@ -30,11 +31,6 @@ export const VideoWrapper = styled(animated.div)<{ $visible: boolean }>`
}
`;
const StyledMobilePlayerControls = css`
background-color: rgba(0, 0, 0, 0.8);
height: 80px;
`;
export const StyledPlayerControls = styled.div<{ $isShow: boolean }>`
position: fixed;
right: 0px;
@ -55,7 +51,10 @@ export const StyledPlayerControls = styled.div<{ $isShow: boolean }>`
rgba(0, 0, 0, 0.89) 100%
);
${isMobile && StyledMobilePlayerControls}
@media ${tablet} {
background-color: rgba(0, 0, 0, 0.8);
height: 80px;
}
`;
export const ControlContainer = styled.div`
@ -71,13 +70,12 @@ export const ControlContainer = styled.div`
justify-content: space-between;
}
${isMobile &&
css`
@media ${tablet} {
margin-top: 8px;
.player_right-control {
margin-right: -8px;
}
`}
}
`;
export const PlayerControlsWrapper = styled.div`
@ -85,13 +83,11 @@ export const PlayerControlsWrapper = styled.div`
width: 100%;
margin-top: 80px;
${isMobile &&
css`
@media ${tablet} {
margin-top: 0px;
`}
}
${isMobileOnly &&
css`
@media ${mobile} {
padding: 0 15px;
`}
}
`;

View File

@ -1,7 +1,11 @@
import lodash from "lodash";
import { useGesture } from "@use-gesture/react";
import { useSpring, animated } from "@react-spring/web";
import { isMobile, isDesktop, isIOS, isMobileOnly } from "react-device-detect";
import {
isDesktop as isDesktopDeviceDetect,
isIOS,
isMobileOnly,
} from "react-device-detect";
import React, {
useCallback,
useEffect,
@ -42,6 +46,7 @@ function ViewerPlayer({
isAudio,
isVideo,
isError,
devices,
audioIcon,
errorTitle,
isLastImage,
@ -72,6 +77,8 @@ function ViewerPlayer({
const isDurationInfinityRef = useRef<boolean>(false);
const { isDesktop, isMobile } = devices;
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isPlaying, setIsPlaying] = useState<boolean>(false);
const [isWaiting, setIsWaiting] = useState<boolean>(false);
@ -232,7 +239,8 @@ function ViewerPlayer({
});
},
onClick: ({ dragging, event }) => {
if (isDesktop && event.target === containerRef.current) return onMask();
if (isDesktopDeviceDetect && event.target === containerRef.current)
return onMask();
if (
dragging ||
@ -385,7 +393,7 @@ function ViewerPlayer({
videoRef.current.play();
setIsPlaying(true);
}
}, [isPlaying, isVideo]);
}, [isPlaying, isVideo, isMobile]);
const handleBigPlayButtonClick = () => {
togglePlay();
@ -612,6 +620,7 @@ function ViewerPlayer({
model={model}
onMaskClick={onMask}
errorTitle={errorTitle}
isMobile={isMobile}
/>
) : (
<StyledPlayerControls

View File

@ -1,5 +1,6 @@
import React, { useMemo, memo, useCallback } from "react";
import equal from "fast-deep-equal/react";
import { useTheme } from "styled-components";
import React, { useMemo, memo, useCallback } from "react";
import Viewer from "../Viewer";
import { isSeparator } from "../../helpers";
@ -12,7 +13,6 @@ import { ContextMenuModel } from "../../types";
import { StyledDropDown } from "../StyledDropDown";
import { StyledDropDownItem } from "../StyledDropDownItem";
import ViewerWrapperProps from "./ViewerWrapper.props";
import { useTheme } from "styled-components";
function ViewerWrapper(props: ViewerWrapperProps) {
const { interfaceDirection } = useTheme();

View File

@ -17,6 +17,12 @@ export type NumberOrString = number | string;
export type NullOrUndefined = null | undefined;
export type DevicesType = {
isMobile: boolean;
isMobileOnly: boolean;
isDesktop: boolean;
};
export type PlaylistType = {
id: number;
canShare: boolean;

View File

@ -2,10 +2,10 @@ import React from "react";
import ModalDialog from "@docspace/components/modal-dialog";
import Text from "@docspace/components/text";
import Button from "@docspace/components/button";
import { providersData } from "@docspace/common/constants";
import { providersData } from "../../constants";
import styled, { css } from "styled-components";
import { ReactSVG } from "react-svg";
import { getProviderTranslation } from "@docspace/common/utils";
import { getProviderTranslation } from "../../utils";
import SsoReactSvgUrl from "PUBLIC_DIR/images/sso.react.svg?url";
import { mobile } from "@docspace/components/utils/device";

View File

@ -2,7 +2,7 @@
import React from "react";
import { Navigate, Route, useLocation } from "react-router-dom";
//import AppLoader from "../AppLoader";
import { combineUrl } from "@docspace/common/utils";
import { combineUrl } from "../../utils";
import { inject, observer } from "mobx-react";
import { TenantStatus } from "../../constants";

View File

@ -1,6 +1,6 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import Backend from "../../utils/i18next-http-backend";
import { LANGUAGE } from "../../constants";
import { loadLanguagePath } from "../../utils";
import { getCookie } from "@docspace/components/utils/cookie";

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/common",
"version": "2.0.0",
"version": "2.0.1",
"private": true,
"scripts": {
"build": "echo 'skip it'",
@ -20,6 +20,7 @@
"mobx": "^6.8.0",
"mobx-react": "^7.6.0",
"moment": "^2.29.4",
"moment-timezone": "^0.5.43",
"prop-types": "^15.8.1",
"query-string": "7.1.3",
"re-resizable": "^6.9.9",

View File

@ -1,7 +1,7 @@
import { makeAutoObservable, runInAction } from "mobx";
import moment from "moment";
import moment from "moment-timezone";
import { getDaysLeft, getDaysRemaining } from "@docspace/common/utils";
import { getDaysLeft, getDaysRemaining } from "../utils";
import api from "../api";
import { TariffState } from "../constants";
@ -77,11 +77,17 @@ class CurrentTariffStatusStore {
get paymentDate() {
moment.locale(this.authStore.language);
if (this.dueDate === null) return "";
return moment(this.dueDate).format("LL");
return moment(this.dueDate)
.tz(window.timezone || "")
.format("LL");
}
isValidDate = (date) => {
return moment(date).year() !== 9999;
return (
moment(date)
.tz(window.timezone || "")
.year() !== 9999
);
};
get isPaymentDateValid() {
if (this.dueDate === null) return false;
@ -91,12 +97,14 @@ class CurrentTariffStatusStore {
get isLicenseDateExpired() {
if (!this.isPaymentDateValid) return;
return moment() > moment(this.dueDate);
return moment() > moment(this.dueDate).tz(window.timezone || "");
}
get gracePeriodEndDate() {
moment.locale(this.authStore.language);
if (this.delayDueDate === null) return "";
return moment(this.delayDueDate).format("LL");
return moment(this.delayDueDate)
.tz(window.timezone || "")
.format("LL");
}
get delayDaysCount() {

View File

@ -1,8 +1,8 @@
import { makeAutoObservable } from "mobx";
import { getUserById } from "@docspace/common/api/people";
import { combineUrl, getUserRole } from "@docspace/common/utils";
import { FolderType } from "@docspace/common/constants";
import { getUserById } from "../api/people";
import { combineUrl, getUserRole } from "../utils";
import { FolderType } from "../constants";
import config from "PACKAGE_FILE";
import Filter from "../api/people/filter";
import { getRoomInfo } from "../api/rooms";
@ -221,15 +221,15 @@ class InfoPanelStore {
getInfoPanelItemIcon = (item, size) => {
return item.isRoom || !!item.roomType
? item.rootFolderType === FolderType.Archive
? this.settingsStore.getIcon(
size,
null,
null,
null,
item.roomType,
true
)
: item.logo && item.logo.medium
? item.logo && item.logo.medium
: this.settingsStore.getIcon(
size,
null,
null,
null,
item.roomType,
true
)
? item.logo.medium
: item.icon
? item.icon

View File

@ -24,7 +24,7 @@ import {
size as deviceSize,
isTablet,
} from "@docspace/components/utils/device";
import { wrongPortalNameUrl } from "@docspace/common/constants";
import { wrongPortalNameUrl } from "../constants";
import { ARTICLE_ALERTS } from "@docspace/client/src/helpers/constants";
import toastr from "@docspace/components/toast/toastr";
//import { getFromLocalStorage } from "@docspace/client/src/pages/PortalSettings/utils";
@ -167,7 +167,7 @@ class SettingsStore {
currentColorScheme = null;
enablePlugins = false;
pluginOptions = [];
pluginOptions = { upload: false, delete: false };
domainValidator = null;
additionalResourcesData = null;
@ -495,7 +495,11 @@ class SettingsStore {
if (origSettings?.plugins?.enabled) {
this.enablePlugins = origSettings.plugins.enabled;
this.pluginOptions = origSettings.plugins.allow;
this.pluginOptions = {
upload: origSettings.plugins.upload,
delete: origSettings.plugins.delete,
};
}
if (origSettings?.tenantAlias) {
@ -965,6 +969,7 @@ class SettingsStore {
};
get isFrame() {
console.log("get isFrame:", this.frameConfig?.name === window.name);
return this.frameConfig?.name === window.name;
}

View File

@ -5,7 +5,7 @@ import { Workbox } from "workbox-window";
import SnackBar from "@docspace/components/snackbar";
import i18n from "i18next";
import { useTranslation, initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import Backend from "../utils/i18next-http-backend";
import { LANGUAGE } from "../constants";
import { getCookie } from "@docspace/components/utils/cookie";

View File

@ -13,8 +13,7 @@ class AxiosClient {
initCSR = () => {
this.isSSR = false;
const origin =
window.DocSpaceConfig?.api?.origin || apiOrigin || window.location.origin;
const origin = window.DocSpaceConfig?.api?.origin || apiOrigin || window.location.origin;
const proxy = window.DocSpaceConfig?.proxy?.url || proxyURL;
const prefix = window.DocSpaceConfig?.api?.prefix || apiPrefix;
@ -30,22 +29,16 @@ class AxiosClient {
const sharedIndex = location.pathname.indexOf("shared");
const lastKeySymbol = location.search.indexOf("&");
const lastIndex =
lastKeySymbol === -1 ? location.search.length : lastKeySymbol;
const lastIndex = lastKeySymbol === -1 ? location.search.length : lastKeySymbol;
const publicRoomKey =
shareIndex > -1 && sharedIndex === -1
? location.search.substring(5, lastIndex)
: null;
shareIndex > -1 && sharedIndex === -1 ? location.search.substring(5, lastIndex) : null;
if (publicRoomKey) {
headers = { ...headers, "Request-Token": publicRoomKey };
}
const apiBaseURL = combineUrl(origin, proxy, prefix);
const paymentsURL = combineUrl(
proxy,
"/portal-settings/payments/portal-payments"
);
const paymentsURL = combineUrl(proxy, "/portal-settings/payments/portal-payments");
this.paymentsURL = paymentsURL;
const apxiosConfig = {
@ -173,8 +166,7 @@ class AxiosClient {
const pathname = window.location.pathname;
const isArchived = pathname.indexOf("/rooms/archived") !== -1;
const isRooms =
pathname.indexOf("/rooms/shared") !== -1 || isArchived;
const isRooms = pathname.indexOf("/rooms/shared") !== -1 || isArchived;
if (isRooms && !skipRedirect) {
setTimeout(() => {
@ -183,6 +175,10 @@ class AxiosClient {
}
break;
case 429:
error = { ...error, message: "Request limit exceeded" };
break;
default:
break;
}

View File

@ -1,4 +1,4 @@
import { FolderType, PageType } from "@docspace/common/constants";
import { FolderType, PageType } from "../constants";
import { isMobile, isTablet } from "@docspace/components/utils/device";

View File

@ -1,5 +1,8 @@
import moment from "moment";
import moment from "moment-timezone";
export const convertTime = (date, locale) => {
return moment(date).locale(locale).format("L, LTS");
return moment(date)
.tz(window.timezone || "")
.locale(locale)
.format("L, LTS");
};

View File

@ -63,8 +63,9 @@ class FirebaseHelper {
!!this.config["projectId"] &&
!!this.config["storageBucket"] &&
!!this.config["messagingSenderId"] &&
!!this.config["appId"] /*&&
this.config["measurementId"]*/
!!this.config["appId"] &&
!window.navigator.userAgent.includes("ZoomWebKit") && // Disabled firebase for Zoom - unknown 403 error inside iframe
!window.navigator.userAgent.includes("ZoomApps")
);
}

View File

@ -15,7 +15,7 @@ import BackgroundPatternPurpleReactSvgUrl from "PUBLIC_DIR/images/background.pat
import BackgroundPatternLightBlueReactSvgUrl from "PUBLIC_DIR/images/background.pattern.lightBlue.react.svg?url";
import BackgroundPatternBlackReactSvgUrl from "PUBLIC_DIR/images/background.pattern.black.react.svg?url";
import moment from "moment";
import moment from "moment-timezone";
import { LANGUAGE, ThemeKeys, RtlLanguages } from "../constants";
import sjcl from "sjcl";
@ -336,7 +336,7 @@ export const isLanguageRtl = (lng: string) => {
// temporary function needed to replace rtl language in Editor to ltr
export const getLtrLanguageForEditor = (
userLng: string,
userLng: string | undefined,
portalLng: string,
isEditor: boolean = false
): string => {
@ -349,7 +349,6 @@ export const getLtrLanguageForEditor = (
if ((!isEditor && !isEditorPath) || (userLng && !isUserLngRtl))
return userLng;
if (portalLng && !isPortalLngRtl) return portalLng;
return "en";
};

View File

@ -72,7 +72,7 @@ Badge.propTypes = {
/** CSS font-size */
fontSize: PropTypes.string,
/** CSS font-weight */
fontWeight: PropTypes.number,
fontWeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** CSS border-radius */
borderRadius: PropTypes.string,
/** CSS padding */

View File

@ -404,7 +404,7 @@ class ContextMenu extends Component {
/>
</div>
)}
<Text className="text" truncate={true}>
<Text className="text" truncate={true} dir="auto">
{this.props.header.title}
</Text>
</div>

View File

@ -18,7 +18,9 @@ import ModalBackdrop from "../components/ModalBackdrop";
import Scrollbar from "../../scrollbar";
import { classNames } from "../../utils/classNames";
import FormWrapper from "../components/FormWrapper";
import { isIOS, isMobileOnly } from "react-device-detect";
import { isIOS, isTablet, isMobile } from "react-device-detect";
let isInitScroll = false;
const Modal = ({
id,
@ -53,17 +55,50 @@ const Modal = ({
const contentRef = React.useRef(0);
React.useEffect(() => {
if (isMobileOnly && isIOS) {
if (isIOS && isMobile) {
window.visualViewport.addEventListener("resize", onResize);
window.visualViewport.addEventListener("scroll", onResize);
}
return () => {
window.visualViewport.removeEventListener("resize", onResize);
window.visualViewport.removeEventListener("scroll", onResize);
};
}, []);
React.useEffect(() => {
if (!visible) isInitScroll = false;
}, [visible]);
const scrollPosition = () => {
if (currentDisplayType !== "modal") return;
if (isInitScroll) return;
const dialogHeader = document
.getElementById("modal-header-swipe")
?.getBoundingClientRect();
const input = document
.getElementsByClassName("input-component")[0]
?.getBoundingClientRect();
if (dialogHeader && input) {
dialogHeader.y < dialogHeader.height + input.height
? window.scrollTo(0, input.y)
: window.scrollTo(0, dialogHeader.y);
}
isInitScroll = true;
};
const onResize = (e) => {
if (window.innerHeight < window.innerWidth || isTablet) {
scrollPosition();
return;
}
if (!contentRef.current) return;
if (currentDisplayType === "modal") {

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/components",
"version": "2.0.0",
"version": "2.0.1",
"private": true,
"scripts": {
"build": "echo 'skip it'",

View File

@ -89,6 +89,7 @@ const Item = React.memo(({ index, style, data }: ItemProps) => {
fontSize={"14px"}
noSelect
truncate
dir="auto"
>
{label}
</Text>

View File

@ -221,7 +221,7 @@ SnackBar.propTypes = {
/** Sets the font size */
fontSize: PropTypes.string,
/** Sets the font weight */
fontWeight: PropTypes.string,
fontWeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Specifies the text alignment */
textAlign: PropTypes.string,
/** Allows displaying content in HTML format */

View File

@ -28,14 +28,14 @@ const Input = ({
return props.mask != null ? (
<MaskedInput
className={`${className} not-selectable`}
className={`${className} input-component not-selectable`}
keepCharPositions={true}
guide={false}
{...props}
/>
) : (
<input
className={`${className} not-selectable`}
className={`${className} input-component not-selectable`}
dir={dir}
{...props}
{...rest}

View File

@ -1,6 +1,11 @@
import moment from "moment";
import moment from "moment-timezone";
export default function getCorrectDate(locale, date) {
export default function getCorrectDate(
locale,
date,
dateFormat = "L",
timeFormat = "LT"
) {
// if something went wrong with 'moment' - change for on this method get correct time
// const options = {
// year: "numeric",
@ -16,8 +21,10 @@ export default function getCorrectDate(locale, date) {
if (!date || date === "0001-01-01T00:00:00.0000000Z") return "—";
const curDate = moment(date).locale(locale).format("L");
const curTime = moment(date).locale(locale).format("LT");
const timezone = window.timezone;
const curDate = moment(date).locale(locale).tz(timezone).format(dateFormat);
const curTime = moment(date).locale(locale).tz(timezone).format(timeFormat);
const correctDate = curDate + " " + curTime;

View File

@ -1,6 +1,6 @@
{
"name": "@docspace/editor",
"version": "2.0.0",
"version": "2.0.1",
"private": true,
"homepage": "/doceditor",
"scripts": {

View File

@ -12,9 +12,14 @@ export const StyledSimpleNav = styled.div`
`;
export const StyledDeepLink = styled.div`
width: 100%;
display: flex;
flex-direction: column;
z-index: 1;
@media ${mobile} {
width: calc(100% - 32px);
}
`;
export const StyledBodyWrapper = styled.div`

Some files were not shown because too many files have changed in this diff Show More