Merge branch 'hotfix/v2.6.1' into develop
# Conflicts: # packages/client/src/pages/PortalSettings/Layout/Section/Header/index.js # packages/client/src/pages/PortalSettings/categories/data-import/NextCloudWorkspace/Stepper/SelectUsersStep/index.js # packages/client/src/pages/PortalSettings/categories/data-import/components/AddEmailsStep/AccountsTable/RowView/UsersRowContent.tsx # packages/client/src/pages/PortalSettings/utils/settingsTree.js
This commit is contained in:
commit
602ce53411
@ -10,13 +10,16 @@
|
||||
"ExpectUsers": "Expect users",
|
||||
"FeedLinkWasDeleted": "Link was deleted",
|
||||
"FeedLocationLabel": "Folder «{{folderTitle}}»",
|
||||
"FeedLocationLabelFrom": "from «{{folderTitle}}»",
|
||||
"FeedLocationRoomLabel": "Room «{{folderTitle}}»",
|
||||
"FileConverted": "File converted.",
|
||||
"FileCopied": "Files copied.",
|
||||
"FileCopiedTo": "Files copied to «{{folderTitle}}»",
|
||||
"FileCreated": "File created.",
|
||||
"FileDeleted": "Files removed.",
|
||||
"FileExtension": "File extension",
|
||||
"FileMoved": "Files moved.",
|
||||
"FileMovedTo": "File moved to «{{folderTitle}}»",
|
||||
"FileRenamed": "File renamed.",
|
||||
"FilesEmptyScreenText": "See file and folder details here",
|
||||
"FileUploaded": "Files added.",
|
||||
|
@ -424,6 +424,7 @@ export default inject(
|
||||
isRestore,
|
||||
isPanelVisible,
|
||||
id,
|
||||
currentFolderId: currentFolderIdProp,
|
||||
}: FilesSelectorProps,
|
||||
) => {
|
||||
const { id: selectedId, parentId, rootFolderType } = selectedFolderStore;
|
||||
@ -551,7 +552,7 @@ export default inject(
|
||||
getIcon,
|
||||
|
||||
roomsFolderId,
|
||||
currentFolderId: folderId,
|
||||
currentFolderId: folderId || currentFolderIdProp,
|
||||
filesSettings,
|
||||
};
|
||||
},
|
||||
|
@ -29,4 +29,8 @@ import { ModalDialog } from "@docspace/shared/components/modal-dialog";
|
||||
|
||||
export const StyledModal = styled(ModalDialog)`
|
||||
user-select: none;
|
||||
|
||||
.modal-body {
|
||||
padding-top: 20px;
|
||||
}
|
||||
`;
|
||||
|
@ -24,8 +24,15 @@
|
||||
// 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
|
||||
|
||||
export const DEFAULT_MIN_COLUMN_SIZE = 110;
|
||||
export const SETTINGS_SIZE = 24;
|
||||
export const CONTAINER_MARGIN = 25;
|
||||
export const MIN_SIZE_FIRST_COLUMN = 210;
|
||||
export const TABLE_HEADER_HEIGHT = 40;
|
||||
import styled from "styled-components";
|
||||
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
|
||||
|
||||
export const StyledModalDialog = styled(ModalDialog)`
|
||||
.modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
margin: 16px 16px 12px;
|
||||
}
|
||||
`;
|
@ -24,23 +24,32 @@
|
||||
// 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 { inject, observer } from "mobx-react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import {
|
||||
ModalDialog,
|
||||
ModalDialogType,
|
||||
} from "@docspace/shared/components/modal-dialog";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import { useState, useEffect, useTransition } from "react";
|
||||
import { getGroupMembersInRoom } from "@docspace/shared/api/groups";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { InputSize } from "@docspace/shared/components/text-input";
|
||||
import { SearchInput } from "@docspace/shared/components/search-input";
|
||||
import GroupMember from "./GroupMember";
|
||||
import {
|
||||
TGroup,
|
||||
TGroupMemberInvitedInRoom,
|
||||
} from "@docspace/shared/api/groups/types";
|
||||
|
||||
import EmptyContainer from "./EmptyContainer";
|
||||
import GroupMembersList from "./sub-components/GroupMembersList/GroupMembersList";
|
||||
import { StyledModalDialog } from "./EditGroupMembersDialog.styled";
|
||||
import { ModalBodyLoader } from "./sub-components/ModalBodyLoader/ModalBodyLoader";
|
||||
import { MIN_LOADER_TIMER } from "@docspace/shared/selectors/Files/FilesSelector.constants";
|
||||
|
||||
interface EditGroupMembersProps {
|
||||
visible: boolean;
|
||||
setVisible: (visible: boolean) => void;
|
||||
group: any;
|
||||
group: TGroup;
|
||||
infoPanelSelection: any;
|
||||
}
|
||||
|
||||
@ -53,33 +62,63 @@ const EditGroupMembers = ({
|
||||
const { t } = useTranslation(["Common"]);
|
||||
|
||||
const [searchValue, setSearchValue] = useState<string>("");
|
||||
const onChangeSearchValue = (newValue: string) => {
|
||||
setSearchValue(newValue);
|
||||
};
|
||||
const onClearSearch = () => onChangeSearchValue("");
|
||||
const [total, setTotal] = useState(0);
|
||||
const [groupMembers, setGroupMembers] = useState<
|
||||
TGroupMemberInvitedInRoom[] | null
|
||||
>(null);
|
||||
const [isSearchResultLoading, setIsSearchResultLoading] = useState(false);
|
||||
const [isNextPageLoading, setIsNextPageLoading] = useState(false);
|
||||
|
||||
const [groupMembers, setGroupMembers] = useState<any[] | null>(null);
|
||||
const filteredGroupMembers = groupMembers?.filter((groupMember) =>
|
||||
groupMember.user.displayName.includes(searchValue),
|
||||
);
|
||||
const [, startTransition] = useTransition();
|
||||
const onChangeSearchValue = (value: string) => {
|
||||
setIsSearchResultLoading(true);
|
||||
setSearchValue(value.trim());
|
||||
};
|
||||
|
||||
const onClearSearch = () => onChangeSearchValue("");
|
||||
|
||||
const onClose = () => setVisible(false);
|
||||
|
||||
const isSearchListEmpty =
|
||||
filteredGroupMembers && !filteredGroupMembers.length;
|
||||
const hasMembers = filteredGroupMembers && filteredGroupMembers.length !== 0;
|
||||
const loadNextPage = async (startIndex: number) => {
|
||||
const startLoadingTime = new Date();
|
||||
|
||||
try {
|
||||
setIsNextPageLoading(true);
|
||||
const filter = { startIndex, count: 100, filterValue: searchValue };
|
||||
|
||||
const data = await getGroupMembersInRoom(
|
||||
infoPanelSelection.id,
|
||||
group.id,
|
||||
filter,
|
||||
);
|
||||
|
||||
setTotal(data.total);
|
||||
if (startIndex === 0 || !groupMembers) {
|
||||
setGroupMembers(data.items);
|
||||
} else {
|
||||
setGroupMembers([...groupMembers, ...data.items]);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
const nowDate = new Date();
|
||||
const diff = Math.abs(nowDate.getTime() - startLoadingTime.getTime());
|
||||
|
||||
if (diff < MIN_LOADER_TIMER) {
|
||||
setTimeout(() => {
|
||||
setIsSearchResultLoading(false);
|
||||
}, MIN_LOADER_TIMER - diff);
|
||||
} else {
|
||||
setIsSearchResultLoading(false);
|
||||
}
|
||||
setIsNextPageLoading(false);
|
||||
// setIsSearchResultLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchGroup = async () => {
|
||||
if (!group) return;
|
||||
|
||||
getGroupMembersInRoom(infoPanelSelection.id, group.id)!
|
||||
.then((data: any) => startTransition(() => setGroupMembers(data.items)))
|
||||
.catch((err: any) => console.error(err));
|
||||
};
|
||||
fetchGroup();
|
||||
}, [group, infoPanelSelection.id]);
|
||||
loadNextPage(0);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchValue]);
|
||||
|
||||
if (!infoPanelSelection?.isRoom) {
|
||||
onClose();
|
||||
@ -87,7 +126,7 @@ const EditGroupMembers = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<ModalDialog
|
||||
<StyledModalDialog
|
||||
visible={visible}
|
||||
onClose={onClose}
|
||||
displayType={ModalDialogType.aside}
|
||||
@ -95,29 +134,40 @@ const EditGroupMembers = ({
|
||||
<ModalDialog.Header>{group.name}</ModalDialog.Header>
|
||||
|
||||
<ModalDialog.Body>
|
||||
<SearchInput
|
||||
className="search-input"
|
||||
placeholder={t("PeopleTranslations:SearchByGroupMembers")}
|
||||
value={searchValue}
|
||||
onChange={onChangeSearchValue}
|
||||
onClearSearch={onClearSearch}
|
||||
size={InputSize.base}
|
||||
/>
|
||||
{!groupMembers ? (
|
||||
<ModalBodyLoader withSearch />
|
||||
) : (
|
||||
<>
|
||||
<SearchInput
|
||||
className="search-input"
|
||||
placeholder={t("PeopleTranslations:SearchByGroupMembers")}
|
||||
value={searchValue}
|
||||
onChange={onChangeSearchValue}
|
||||
onClearSearch={onClearSearch}
|
||||
size={InputSize.base}
|
||||
/>
|
||||
|
||||
<div style={{ height: "12px", width: "100%" }} />
|
||||
|
||||
{isSearchListEmpty && <EmptyContainer />}
|
||||
|
||||
{hasMembers &&
|
||||
filteredGroupMembers.map(({ user, ...rest }) => (
|
||||
<GroupMember t={t} key={user.id} user={{ ...user, ...rest }} />
|
||||
))}
|
||||
{isSearchResultLoading ? (
|
||||
<ModalBodyLoader withSearch={false} />
|
||||
) : !groupMembers.length ? (
|
||||
<EmptyContainer />
|
||||
) : (
|
||||
<GroupMembersList
|
||||
members={groupMembers}
|
||||
loadNextPage={loadNextPage}
|
||||
hasNextPage={groupMembers.length < total}
|
||||
total={total}
|
||||
isNextPageLoading={isNextPageLoading}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ModalDialog.Body>
|
||||
</ModalDialog>
|
||||
</StyledModalDialog>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ infoPanelStore, userStore, dialogsStore }) => ({
|
||||
export default inject(({ infoPanelStore, userStore, dialogsStore }: any) => ({
|
||||
infoPanelSelection: infoPanelStore.infoPanelSelection,
|
||||
selfId: userStore.user.id,
|
||||
group: dialogsStore.editMembersGroup,
|
||||
|
@ -31,7 +31,7 @@ export const GroupMember = styled.div<{ isExpect: boolean }>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
padding: 8px 16px;
|
||||
|
||||
.avatar {
|
||||
min-width: 32px;
|
@ -24,39 +24,47 @@
|
||||
// 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 { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { isMobile, isMobileOnly } from "react-device-detect";
|
||||
|
||||
import AtReactSvgUrl from "PUBLIC_DIR/images/@.react.svg?url";
|
||||
// import { StyledUser } from "../../styles/members";
|
||||
import { Avatar } from "@docspace/shared/components/avatar";
|
||||
import { ComboBox } from "@docspace/shared/components/combobox";
|
||||
import DefaultUserPhotoUrl from "PUBLIC_DIR/images/default_user_photo_size_82-82.png";
|
||||
import { isMobileOnly, isMobile } from "react-device-detect";
|
||||
import { decode } from "he";
|
||||
import { filterUserRoleOptions } from "SRC_DIR/helpers";
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import * as Styled from "./index.styled";
|
||||
import { getUserRoleOptionsByUserAccess } from "@docspace/shared/utils/room-members/getUserRoleOptionsByUserAccess";
|
||||
import { getUserRoleOptionsByRoomType } from "@docspace/shared/utils/room-members/getUserRoleOptionsByRoomType";
|
||||
import { updateRoomMemberRole } from "@docspace/shared/api/rooms";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { useState } from "react";
|
||||
import { HelpButton } from "@docspace/shared/components/help-button";
|
||||
import { getUserRoleOptions } from "@docspace/shared/utils/room-members/getUserRoleOptions";
|
||||
import { ShareAccessRights } from "@docspace/shared/enums";
|
||||
import { getUserRole, getUserTypeLabel } from "@docspace/shared/utils/common";
|
||||
import { getUserRole } from "@docspace/shared/utils/common";
|
||||
import { TGroupMemberInvitedInRoom } from "@docspace/shared/api/groups/types";
|
||||
|
||||
import * as Styled from "./index.styled";
|
||||
|
||||
interface GroupMemberProps {
|
||||
t: any;
|
||||
user: any;
|
||||
member: TGroupMemberInvitedInRoom;
|
||||
infoPanelSelection: any;
|
||||
}
|
||||
|
||||
const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
||||
const GroupMember = ({ member, infoPanelSelection }: GroupMemberProps) => {
|
||||
const { user } = member;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { t } = useTranslation("Common");
|
||||
|
||||
const userRole = user.isOwner
|
||||
? getUserRoleOptions(t).portalAdmin
|
||||
: getUserRoleOptionsByUserAccess(t, user.userAccess || user.groupAccess);
|
||||
: getUserRoleOptionsByUserAccess(
|
||||
t,
|
||||
member.userAccess || member.groupAccess,
|
||||
);
|
||||
|
||||
const fullRoomRoleOptions = getUserRoleOptionsByRoomType(
|
||||
t,
|
||||
@ -86,7 +94,7 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
||||
else
|
||||
selectedUserRoleCBOption = getUserRoleOptionsByUserAccess(
|
||||
t,
|
||||
user.userAccess || user.groupAccess,
|
||||
member.userAccess || member.groupAccess,
|
||||
);
|
||||
|
||||
const availableUserRoleCBOptions = filterUserRoleOptions(
|
||||
@ -101,7 +109,7 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
||||
notify: false,
|
||||
sharingMessage: "",
|
||||
})
|
||||
.then(() => (user.userAccess = userRoleOption.access))
|
||||
.then(() => (member.userAccess = userRoleOption.access))
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
@ -134,8 +142,8 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
||||
</div>
|
||||
|
||||
<div className="individual-rights-tooltip">
|
||||
{user.userAccess &&
|
||||
user.userAccess !== user.groupAccess &&
|
||||
{member.userAccess &&
|
||||
member.userAccess !== member.groupAccess &&
|
||||
!user.isOwner && (
|
||||
<HelpButton
|
||||
place="left"
|
||||
@ -152,7 +160,7 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
||||
|
||||
{userRole && userRoleOptions && (
|
||||
<div className="role-wrapper">
|
||||
{user.canEditAccess && !user.isOwner ? (
|
||||
{member.canEditAccess && !user.isOwner ? (
|
||||
<ComboBox
|
||||
className="role-combobox"
|
||||
selectedOption={userRole}
|
||||
@ -180,6 +188,6 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ infoPanelStore }) => ({
|
||||
export default inject(({ infoPanelStore }: any) => ({
|
||||
infoPanelSelection: infoPanelStore.infoPanelSelection,
|
||||
}))(observer(GroupMember));
|
@ -0,0 +1,126 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// 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 React, { memo, useCallback } from "react";
|
||||
import { useTheme } from "styled-components";
|
||||
import { areEqual, FixedSizeList as List } from "react-window";
|
||||
import AutoSizer from "react-virtualized-auto-sizer";
|
||||
import InfiniteLoader from "react-window-infinite-loader";
|
||||
|
||||
import { Scrollbar } from "@docspace/shared/components/scrollbar";
|
||||
import { RowLoader } from "@docspace/shared/skeletons/selector";
|
||||
import { TGroupMemberInvitedInRoom } from "@docspace/shared/api/groups/types";
|
||||
|
||||
import GroupMember from "../GroupMember";
|
||||
|
||||
const ROW_HEIGHT = 48;
|
||||
const SEARCH_WITH_PADDING_HEIGHT = 60;
|
||||
|
||||
const Row = memo(
|
||||
({
|
||||
data,
|
||||
index,
|
||||
style,
|
||||
}: {
|
||||
data: TGroupMemberInvitedInRoom[];
|
||||
index: number;
|
||||
style: React.CSSProperties;
|
||||
}) => {
|
||||
const member = data[index];
|
||||
|
||||
return (
|
||||
<div style={style}>
|
||||
{member ? (
|
||||
<GroupMember member={member} />
|
||||
) : (
|
||||
<RowLoader isMultiSelect={false} isContainer isUser />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
areEqual,
|
||||
);
|
||||
|
||||
Row.displayName = "Row";
|
||||
|
||||
interface GroupMembersListProps {
|
||||
members: TGroupMemberInvitedInRoom[];
|
||||
loadNextPage: (startIndex: number) => void;
|
||||
hasNextPage: boolean;
|
||||
total: number;
|
||||
isNextPageLoading: boolean;
|
||||
}
|
||||
|
||||
const GroupMembersList = ({
|
||||
members,
|
||||
loadNextPage,
|
||||
hasNextPage,
|
||||
total,
|
||||
isNextPageLoading,
|
||||
}: GroupMembersListProps) => {
|
||||
const { interfaceDirection } = useTheme();
|
||||
|
||||
const itemCount = hasNextPage ? members.length + 1 : members.length;
|
||||
|
||||
const isItemLoaded = useCallback(
|
||||
(index: number) => {
|
||||
return !hasNextPage || index < itemCount - 1;
|
||||
},
|
||||
[hasNextPage, itemCount],
|
||||
);
|
||||
|
||||
const loadMoreItems = isNextPageLoading ? () => {} : loadNextPage;
|
||||
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ height, width }) => (
|
||||
<InfiniteLoader
|
||||
isItemLoaded={isItemLoaded}
|
||||
itemCount={total}
|
||||
loadMoreItems={loadMoreItems}
|
||||
>
|
||||
{({ onItemsRendered, ref }) => (
|
||||
<List
|
||||
ref={ref}
|
||||
direction={interfaceDirection}
|
||||
height={height - SEARCH_WITH_PADDING_HEIGHT}
|
||||
width={width}
|
||||
itemCount={itemCount}
|
||||
itemSize={ROW_HEIGHT}
|
||||
itemData={members}
|
||||
outerElementType={Scrollbar}
|
||||
onItemsRendered={onItemsRendered}
|
||||
>
|
||||
{Row}
|
||||
</List>
|
||||
)}
|
||||
</InfiniteLoader>
|
||||
)}
|
||||
</AutoSizer>
|
||||
);
|
||||
};
|
||||
|
||||
export default GroupMembersList;
|
@ -0,0 +1,44 @@
|
||||
// (c) Copyright Ascensio System SIA 2009-2024
|
||||
//
|
||||
// This program is a free software product.
|
||||
// You can redistribute it and/or modify it under the terms
|
||||
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
|
||||
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
|
||||
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
|
||||
// any third-party rights.
|
||||
//
|
||||
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
|
||||
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
|
||||
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||||
//
|
||||
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
|
||||
//
|
||||
// The interactive user interfaces in modified source and object code versions of the Program must
|
||||
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
|
||||
//
|
||||
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
|
||||
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
|
||||
// trademark law for use of our trademarks.
|
||||
//
|
||||
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
|
||||
// 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 { SearchLoader } from "@docspace/shared/skeletons/selector";
|
||||
import React from "react";
|
||||
import { MemberLoader } from "@docspace/shared/skeletons/info-panel/body/views/MembersLoader";
|
||||
|
||||
interface ModalBodyLoaderProps {
|
||||
withSearch: boolean;
|
||||
}
|
||||
|
||||
export const ModalBodyLoader = ({ withSearch }: ModalBodyLoaderProps) => {
|
||||
return (
|
||||
<div style={{ paddingTop: withSearch ? "16px" : "0" }}>
|
||||
{withSearch && <SearchLoader />}
|
||||
<div style={{ paddingInline: "16px" }}>
|
||||
<MemberLoader count={25} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -24,7 +24,7 @@
|
||||
// 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 { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled, { css } from "styled-components";
|
||||
import { Aside } from "@docspace/shared/components/aside";
|
||||
@ -83,20 +83,12 @@ const ChangeRoomOwner = (props) => {
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener("keyup", onKeyUp, false);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keyup", onKeyUp, false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onKeyUp = (e) => {
|
||||
if (e.keyCode === 27) onClose();
|
||||
if (e.keyCode === 13 || e.which === 13) onChangeRoomOwner();
|
||||
};
|
||||
|
||||
const onChangeRoomOwner = async (user, isChecked) => {
|
||||
const onChangeRoomOwner = async (
|
||||
user,
|
||||
selectedAccess,
|
||||
newFooterInputValue,
|
||||
isChecked,
|
||||
) => {
|
||||
if (showBackButton) {
|
||||
setRoomParams && setRoomParams(user[0]);
|
||||
} else {
|
||||
|
@ -96,14 +96,8 @@ const StyledFileRow = styled(Row)`
|
||||
.password-input {
|
||||
position: absolute;
|
||||
top: 48px;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
? css`
|
||||
right: 16px;
|
||||
`
|
||||
: css`
|
||||
left: 16px;
|
||||
`}
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
max-width: 470px;
|
||||
width: calc(100% - 16px);
|
||||
display: flex;
|
||||
|
@ -33,6 +33,9 @@ import { useTheme } from "styled-components";
|
||||
|
||||
const StyledLoadErrorIcon = styled(LoadErrorIcon)`
|
||||
outline: none !important;
|
||||
path {
|
||||
fill: ${(props) => props.theme.filesPanels.upload.iconColor};
|
||||
}
|
||||
`;
|
||||
|
||||
const ErrorFileUpload = ({
|
||||
|
27
packages/client/src/helpers/language-helpers.js
Normal file
27
packages/client/src/helpers/language-helpers.js
Normal file
@ -0,0 +1,27 @@
|
||||
import { getLanguage } from "@docspace/shared/utils";
|
||||
import { translations } from "./autoGeneratedTranslations";
|
||||
|
||||
export function loadLanguagePath(homepage, fixedNS = null) {
|
||||
return (lng, ns) => {
|
||||
const language = getLanguage(lng instanceof Array ? lng[0] : lng);
|
||||
|
||||
const lngCollection = translations?.get(language);
|
||||
|
||||
const data = lngCollection?.get(`${fixedNS || ns}`);
|
||||
|
||||
if (!data) return `/locales/${language}/${fixedNS || ns}.json`;
|
||||
|
||||
let path = data?.split("/");
|
||||
const length = path?.length;
|
||||
|
||||
const isCommonPath = path[length - 1].indexOf("Common") > -1;
|
||||
|
||||
path = `/${path[length - 3]}/${path[length - 2]}/${path[length - 1]}`;
|
||||
|
||||
if (ns.length > 0 && ns[0] === "Common" && isCommonPath) {
|
||||
return `/static${path}`;
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
}
|
@ -25,12 +25,10 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { authStore } from "@docspace/shared/store";
|
||||
import { getLanguage } from "@docspace/shared/utils";
|
||||
import { toCommunityHostname } from "@docspace/shared/utils/common";
|
||||
|
||||
import { CategoryType } from "./constants";
|
||||
import { FolderType, ShareAccessRights } from "@docspace/shared/enums";
|
||||
import { translations } from "./autoGeneratedTranslations";
|
||||
import { FolderType } from "@docspace/shared/enums";
|
||||
|
||||
// import router from "SRC_DIR/router";
|
||||
import i18n from "../i18n";
|
||||
|
||||
@ -54,31 +52,6 @@ export const setDocumentTitle = (subTitle = "") => {
|
||||
document.title = title;
|
||||
};
|
||||
|
||||
export function loadLanguagePath(homepage, fixedNS = null) {
|
||||
return (lng, ns) => {
|
||||
const language = getLanguage(lng instanceof Array ? lng[0] : lng);
|
||||
|
||||
const lngCollection = translations?.get(language);
|
||||
|
||||
const data = lngCollection?.get(`${fixedNS || ns}`);
|
||||
|
||||
if (!data) return `/locales/${language}/${fixedNS || ns}.json`;
|
||||
|
||||
let path = data?.split("/");
|
||||
const length = path?.length;
|
||||
|
||||
const isCommonPath = path[length - 1].indexOf("Common") > -1;
|
||||
|
||||
path = `/${path[length - 3]}/${path[length - 2]}/${path[length - 1]}`;
|
||||
|
||||
if (ns.length > 0 && ns[0] === "Common" && isCommonPath) {
|
||||
return `/static${path}`;
|
||||
}
|
||||
|
||||
return path;
|
||||
};
|
||||
}
|
||||
|
||||
export const checkIfModuleOld = (link) => {
|
||||
if (
|
||||
!link ||
|
||||
|
@ -31,7 +31,7 @@ import config from "PACKAGE_FILE";
|
||||
import { LANGUAGE } from "@docspace/shared/constants";
|
||||
import { getCookie } from "@docspace/shared/utils";
|
||||
|
||||
import { loadLanguagePath } from "./helpers/utils";
|
||||
import { loadLanguagePath } from "./helpers/language-helpers";
|
||||
|
||||
const newInstance = i18n.createInstance();
|
||||
|
||||
|
@ -32,7 +32,7 @@ import FilesFilter from "@docspace/shared/api/files/filter";
|
||||
import RoomsFilter from "@docspace/shared/api/rooms/filter";
|
||||
import { getGroup } from "@docspace/shared/api/groups";
|
||||
import { getUserById } from "@docspace/shared/api/people";
|
||||
import { MEDIA_VIEW_URL } from "@docspace/shared/constants";
|
||||
import { CREATED_FORM_KEY, MEDIA_VIEW_URL } from "@docspace/shared/constants";
|
||||
|
||||
import {
|
||||
Events,
|
||||
@ -78,6 +78,7 @@ const useFiles = ({
|
||||
|
||||
scrollToTop,
|
||||
selectedFolderStore,
|
||||
wsCreatedPDFForm,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams();
|
||||
@ -292,7 +293,15 @@ const useFiles = ({
|
||||
);
|
||||
} else {
|
||||
const folderId = filter.folder;
|
||||
return fetchFiles(folderId, filter);
|
||||
return fetchFiles(folderId, filter)?.finally(() => {
|
||||
const data = sessionStorage.getItem(CREATED_FORM_KEY);
|
||||
if (data) {
|
||||
wsCreatedPDFForm({
|
||||
data,
|
||||
});
|
||||
sessionStorage.removeItem(CREATED_FORM_KEY);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,7 +315,7 @@ const useFiles = ({
|
||||
|
||||
const isFormRoom =
|
||||
selectedFolderStore.roomType === RoomsType.FormRoom ||
|
||||
selectedFolderStore.type === FolderType.FormRoom;
|
||||
selectedFolderStore.parentRoomType === FolderType.FormRoom;
|
||||
|
||||
const payload = {
|
||||
extension: "pdf",
|
||||
|
@ -122,7 +122,8 @@ const StyledHistoryBlockMessage = styled.div`
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.folder-label {
|
||||
.folder-label,
|
||||
.source-folder-label {
|
||||
max-width: 100%;
|
||||
color: ${(props) => props.theme.infoPanel.history.locationIconColor};
|
||||
text-overflow: ellipsis;
|
||||
@ -130,6 +131,10 @@ const StyledHistoryBlockMessage = styled.div`
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.source-folder-label {
|
||||
color: ${(props) => props.theme.infoPanel.history.messageColor};
|
||||
}
|
||||
|
||||
.old-role {
|
||||
color: ${(props) => props.theme.infoPanel.history.oldRoleColor};
|
||||
font-weight: 600;
|
||||
|
@ -40,24 +40,38 @@ const HistoryMainTextFolderInfo = ({
|
||||
feed,
|
||||
selectedFolderId,
|
||||
}: HistoryMainTextFolderInfoProps) => {
|
||||
if (
|
||||
feed.data.parentId === selectedFolderId ||
|
||||
feed.data.toFolderId === selectedFolderId
|
||||
)
|
||||
const {
|
||||
parentId,
|
||||
toFolderId,
|
||||
parentTitle,
|
||||
parentType,
|
||||
fromParentType,
|
||||
fromParentTitle,
|
||||
} = feed.data;
|
||||
|
||||
if (parentId === selectedFolderId || toFolderId === selectedFolderId)
|
||||
return null;
|
||||
|
||||
const destination =
|
||||
feed.data.parentType === 0 || feed.data.toParentType === 0
|
||||
? t("FeedLocationLabel", {
|
||||
folderTitle: feed.data.parentTitle || feed.data.toFolderTitle,
|
||||
})
|
||||
: t("FeedLocationRoomLabel", {
|
||||
folderTitle: feed.data.parentTitle || feed.data.toFolderTitle,
|
||||
});
|
||||
if (!parentTitle) return null;
|
||||
|
||||
const isFolder = parentType === 0;
|
||||
const isFromFolder = fromParentType === 0;
|
||||
|
||||
const destination = isFolder
|
||||
? t("FeedLocationLabel", { folderTitle: parentTitle })
|
||||
: t("FeedLocationRoomLabel", { folderTitle: parentTitle });
|
||||
|
||||
const sourceDestination = isFromFolder
|
||||
? t("FeedLocationLabelFrom", { folderTitle: fromParentTitle })
|
||||
: t("FeedLocationRoomLabel", { folderTitle: parentTitle });
|
||||
|
||||
const className = isFromFolder ? "source-folder-label" : "folder-label";
|
||||
|
||||
return (
|
||||
<StyledHistoryBlockMessage className="message">
|
||||
<span className="folder-label">{destination}</span>
|
||||
<span className={className}>
|
||||
{isFromFolder ? sourceDestination : destination}
|
||||
</span>
|
||||
</StyledHistoryBlockMessage>
|
||||
);
|
||||
};
|
||||
|
@ -114,7 +114,7 @@ export default inject<TStore>(({ dialogsStore, infoPanelStore }) => {
|
||||
const { infoPanelSelection } = infoPanelStore;
|
||||
const { setLinkParams, setEditLinkPanelIsVisible } = dialogsStore;
|
||||
const { id, roomType, security } = infoPanelSelection!;
|
||||
const { EditRoom } = security!;
|
||||
const { EditRoom } = security || {};
|
||||
|
||||
const isFormRoom = roomType === RoomsType.FormRoom;
|
||||
|
||||
|
@ -18,8 +18,18 @@ export const useFeedTranslation = (
|
||||
case "FileRenamed":
|
||||
return t("InfoPanel:FileRenamed");
|
||||
case "FileMoved":
|
||||
if (feed.data.fromParentTitle) {
|
||||
return t("InfoPanel:FileMovedTo", {
|
||||
folderTitle: feed.data.parentTitle,
|
||||
});
|
||||
}
|
||||
return t("InfoPanel:FileMoved");
|
||||
case "FileCopied":
|
||||
if (feed.data.fromParentTitle) {
|
||||
return t("InfoPanel:FileCopiedTo", {
|
||||
folderTitle: feed.data.parentTitle,
|
||||
});
|
||||
}
|
||||
return t("InfoPanel:FileCopied");
|
||||
case "FileDeleted":
|
||||
return t("InfoPanel:FileDeleted");
|
||||
|
@ -61,6 +61,8 @@ class GroupsTableHeader extends React.Component {
|
||||
];
|
||||
|
||||
const columns = props.getColumns(defaultColumns);
|
||||
const tableColumns = columns.map((c) => c.enable && c.key);
|
||||
this.setTableColumns(tableColumns);
|
||||
|
||||
this.state = { columns };
|
||||
}
|
||||
@ -77,7 +79,7 @@ class GroupsTableHeader extends React.Component {
|
||||
this.setState({ columns });
|
||||
|
||||
const tableColumns = columns.map((c) => c.enable && c.key);
|
||||
localStorage.setItem(`${TABLE_COLUMNS}=${this.props.userId}`, tableColumns);
|
||||
this.setTableColumns(tableColumns);
|
||||
|
||||
const event = new Event(Events.CHANGE_COLUMN);
|
||||
window.dispatchEvent(event);
|
||||
@ -103,6 +105,10 @@ class GroupsTableHeader extends React.Component {
|
||||
navigate(`${location.pathname}?${newFilter.toUrlParams()}`);
|
||||
};
|
||||
|
||||
setTableColumns = (tableColumns) => {
|
||||
localStorage.setItem(`${TABLE_COLUMNS}=${this.props.userId}`, tableColumns);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { columns } = this.state;
|
||||
const {
|
||||
|
@ -102,6 +102,8 @@ class InsideGroupTableHeader extends React.Component {
|
||||
});
|
||||
|
||||
const columns = props.getColumns(defaultColumns);
|
||||
const tableColumns = columns.map((c) => c.enable && c.key);
|
||||
this.setTableColumns(tableColumns);
|
||||
|
||||
this.state = { columns };
|
||||
}
|
||||
@ -118,7 +120,7 @@ class InsideGroupTableHeader extends React.Component {
|
||||
this.setState({ columns });
|
||||
|
||||
const tableColumns = columns.map((c) => c.enable && c.key);
|
||||
localStorage.setItem(`${TABLE_COLUMNS}=${this.props.userId}`, tableColumns);
|
||||
this.setTableColumns(tableColumns);
|
||||
|
||||
const event = new Event(Events.CHANGE_COLUMN);
|
||||
|
||||
@ -156,6 +158,10 @@ class InsideGroupTableHeader extends React.Component {
|
||||
navigate(`${location.pathname}?${newFilter.toUrlParams()}`);
|
||||
};
|
||||
|
||||
setTableColumns = (tableColumns) => {
|
||||
localStorage.setItem(`${TABLE_COLUMNS}=${this.props.userId}`, tableColumns);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { columns } = this.state;
|
||||
const {
|
||||
|
@ -160,6 +160,7 @@ const PureHome = (props) => {
|
||||
getFolderModel,
|
||||
scrollToTop,
|
||||
isEmptyGroups,
|
||||
wsCreatedPDFForm,
|
||||
} = props;
|
||||
|
||||
//console.log(t("ComingSoon"))
|
||||
@ -206,6 +207,7 @@ const PureHome = (props) => {
|
||||
|
||||
scrollToTop,
|
||||
selectedFolderStore,
|
||||
wsCreatedPDFForm,
|
||||
});
|
||||
|
||||
const { showUploadPanel } = useOperations({
|
||||
@ -500,6 +502,7 @@ export default inject(
|
||||
removeTagsFromRoom,
|
||||
getRooms,
|
||||
scrollToTop,
|
||||
wsCreatedPDFForm,
|
||||
} = filesStore;
|
||||
|
||||
const { updateProfileCulture } = peopleStore.targetUserStore;
|
||||
@ -564,8 +567,15 @@ export default inject(
|
||||
const { usersStore, groupsStore, viewAs: accountsViewAs } = peopleStore;
|
||||
|
||||
const { getUsersList: fetchPeople } = usersStore;
|
||||
const { getGroups: fetchGroups, fetchGroup, groups } = groupsStore;
|
||||
const isEmptyGroups = (groups && groups.length === 0) || !Boolean(groups);
|
||||
const {
|
||||
getGroups: fetchGroups,
|
||||
fetchGroup,
|
||||
groups,
|
||||
groupsIsFiltered,
|
||||
} = groupsStore;
|
||||
const isEmptyGroups =
|
||||
!groupsIsFiltered &&
|
||||
((groups && groups.length === 0) || !Boolean(groups));
|
||||
|
||||
if (!firstLoad) {
|
||||
if (isLoading) {
|
||||
@ -679,6 +689,7 @@ export default inject(
|
||||
getFolderModel,
|
||||
scrollToTop,
|
||||
isEmptyGroups,
|
||||
wsCreatedPDFForm,
|
||||
};
|
||||
},
|
||||
)(observer(Home));
|
||||
|
@ -73,8 +73,6 @@ export const HeaderContainer = styled.div`
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
color: ${(props) => props.theme.client.settings.headerTitleColor};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.action-wrapper {
|
||||
@ -371,17 +369,10 @@ const SectionHeaderContent = (props) => {
|
||||
<LoaderSectionHeader />
|
||||
) : (
|
||||
<HeaderContainer>
|
||||
{!isCategoryOrHeader && arrayOfParams[0] && (
|
||||
<IconButton
|
||||
iconName={ArrowPathReactSvgUrl}
|
||||
size="17"
|
||||
isFill={true}
|
||||
onClick={onBackToParent}
|
||||
className="arrow-button"
|
||||
/>
|
||||
)}
|
||||
<Headline type="content" truncate={true}>
|
||||
{isMobile() && isServicePage && (
|
||||
{!isCategoryOrHeader &&
|
||||
arrayOfParams[0] &&
|
||||
(isMobile() ||
|
||||
window.location.href.indexOf("/javascript-sdk/") > -1) && (
|
||||
<IconButton
|
||||
iconName={ArrowPathReactSvgUrl}
|
||||
size="17"
|
||||
@ -390,6 +381,7 @@ const SectionHeaderContent = (props) => {
|
||||
className="arrow-button"
|
||||
/>
|
||||
)}
|
||||
<Headline type="content" truncate={true}>
|
||||
<div className="settings-section_header">
|
||||
<div className="header">{translatedHeader}</div>
|
||||
{isNeedPaidIcon ? (
|
||||
|
@ -62,6 +62,7 @@ const UsersRow = (props: AddEmailUsersRowProps) => {
|
||||
onRowClick={handleAccountToggle}
|
||||
onSelect={toggleAccount}
|
||||
isDisabled={!isPrevEmailValid}
|
||||
contextButtonSpacerWidth="0"
|
||||
>
|
||||
<UsersRowContent
|
||||
id={data.key}
|
||||
|
@ -60,6 +60,9 @@ const DecisionButton = styled(Button)`
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
path {
|
||||
fill: ${(props) => props.theme.client.settings.migration.tableHeaderText};
|
||||
}
|
||||
`;
|
||||
|
||||
DecisionButton.defaultProps = { theme: Base };
|
||||
@ -82,13 +85,19 @@ const StyledRowContent = styled(RowContent)`
|
||||
|
||||
.user-email {
|
||||
margin-inline-end: 5px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: ${(props) =>
|
||||
props.theme.client.settings.migration.tableRowTextColor};
|
||||
|
||||
path {
|
||||
fill: #a3a9ae;
|
||||
fill: ${(props) => props.theme.client.settings.migration.tableHeaderText};
|
||||
}
|
||||
}
|
||||
|
||||
.row-main-container-wrapper {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mainIcons {
|
||||
@ -179,7 +188,7 @@ const UsersRowContent = (props: AddEmailRowContentProps) => {
|
||||
<Text fontWeight={600} fontSize="14px">
|
||||
{displayName}
|
||||
</Text>
|
||||
<Text fontWeight={600} fontSize="12px" color="#A3A9AE">
|
||||
<Text className="user-email">
|
||||
{prevEmail === "" ? t("Settings:NoEmail") : prevEmail}
|
||||
</Text>
|
||||
</div>
|
||||
|
@ -37,13 +37,7 @@ import UsersRow from "./UsersRow";
|
||||
import { AddEmailRowProps, RowViewProps } from "../../../../types";
|
||||
|
||||
const StyledRowContainer = styled(RowContainer)`
|
||||
margin-bottom: 20px;
|
||||
|
||||
.row-main-container-wrapper {
|
||||
@media ${tablet} {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
margin: 0 0 20px;
|
||||
`;
|
||||
|
||||
const StyledRow = styled(Row)`
|
||||
@ -51,6 +45,12 @@ const StyledRow = styled(Row)`
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
|
||||
.row-header-title {
|
||||
color: ${(props) => props.theme.client.settings.migration.tableHeaderText};
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
.row_content {
|
||||
height: auto;
|
||||
@ -101,9 +101,7 @@ const RowView = (props: RowViewProps) => {
|
||||
indeterminate={isIndeterminate}
|
||||
isDisabled={usersWithFilledEmails.length === 0}
|
||||
>
|
||||
<Text color="#a3a9ae" fontWeight={600} fontSize="12px">
|
||||
{t("Common:Name")}
|
||||
</Text>
|
||||
<Text className="row-header-title">{t("Common:Name")}</Text>
|
||||
</StyledRow>
|
||||
{accountsData.map((data) => (
|
||||
<UsersRow
|
||||
|
@ -64,25 +64,27 @@ const StyledTableRow = styled(TableRow)`
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
overflow: hidden;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: ${(props) =>
|
||||
props.theme.client.settings.migration.tableRowTextColor};
|
||||
|
||||
path {
|
||||
fill: #a3a9ae;
|
||||
fill: ${(props) => props.theme.client.settings.migration.tableHeaderText};
|
||||
}
|
||||
}
|
||||
|
||||
.import-email-input {
|
||||
width: 357.67px;
|
||||
}
|
||||
|
||||
.textOverflow {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
`;
|
||||
|
||||
const DecisionButton = styled(Button)`
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
path {
|
||||
fill: ${(props) => props.theme.client.settings.migration.tableHeaderText};
|
||||
}
|
||||
`;
|
||||
|
||||
DecisionButton.defaultProps = { theme: Base };
|
||||
@ -199,7 +201,7 @@ const UsersTableRow = (props: AddEmailTableRowProps) => {
|
||||
isChecked={isChecked}
|
||||
isDisabled={!isPrevEmailValid}
|
||||
/>
|
||||
<Text fontWeight={600} className="textOverflow">
|
||||
<Text fontWeight={600} truncate>
|
||||
{displayName}
|
||||
</Text>
|
||||
</TableCell>
|
||||
@ -230,7 +232,7 @@ const UsersTableRow = (props: AddEmailTableRowProps) => {
|
||||
) : (
|
||||
<span onClick={openEmail} className="user-email" ref={emailTextRef}>
|
||||
<EditSvg />
|
||||
<Text fontWeight={600} color="#A3A9AE" className="textOverflow">
|
||||
<Text className="user-email" truncate>
|
||||
{prevEmail !== "" ? prevEmail : t("Settings:NoEmail")}
|
||||
</Text>
|
||||
</span>
|
||||
|
@ -75,10 +75,7 @@ const LDAP = ({
|
||||
|
||||
if (!isLoaded && isLdapAvailable) return <LdapLoader />;
|
||||
return (
|
||||
<StyledLdapPage
|
||||
isSmallWindow={isSmallWindow}
|
||||
isSettingPaid={isLdapAvailable}
|
||||
>
|
||||
<StyledLdapPage isSmallWindow={isSmallWindow}>
|
||||
<Text className="intro-text settings_unavailable">{t("LdapIntro")}</Text>
|
||||
<Box marginProp="8px 0 24px 0">
|
||||
<Link
|
||||
|
@ -27,7 +27,6 @@
|
||||
import styled, { css } from "styled-components";
|
||||
import { Box } from "@docspace/shared/components/box";
|
||||
import { mobile } from "@docspace/shared/utils";
|
||||
import { UnavailableStyles } from "../../../../utils/commonSettingsStyles";
|
||||
|
||||
const StyledLdapPage = styled(Box)`
|
||||
max-width: ${(props) => (props.isSmallWindow ? "100%" : "700px")};
|
||||
@ -222,8 +221,6 @@ const StyledLdapPage = styled(Box)`
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
${(props) => !props.isSettingPaid && UnavailableStyles}
|
||||
`;
|
||||
|
||||
export default StyledLdapPage;
|
||||
|
@ -33,22 +33,14 @@ import { Text } from "@docspace/shared/components/text";
|
||||
|
||||
const HideButton = (props) => {
|
||||
const { t } = useTranslation("SingleSignOn");
|
||||
const {
|
||||
text,
|
||||
label,
|
||||
isAdditionalParameters,
|
||||
value,
|
||||
setIsSettingsShown,
|
||||
isDisabled,
|
||||
} = props;
|
||||
const { text, label, isAdditionalParameters, value, setIsSettingsShown } =
|
||||
props;
|
||||
const marginProp = isAdditionalParameters ? null : "24px 0";
|
||||
|
||||
const onClick = () => {
|
||||
setIsSettingsShown(!value);
|
||||
};
|
||||
|
||||
const onClickProp = isDisabled ? {} : { onClick: onClick };
|
||||
|
||||
return (
|
||||
<Box
|
||||
alignItems="center"
|
||||
@ -71,7 +63,7 @@ const HideButton = (props) => {
|
||||
<Link
|
||||
className="hide-button settings_unavailable"
|
||||
isHovered
|
||||
{...onClickProp}
|
||||
onClick={onClick}
|
||||
type="action"
|
||||
>
|
||||
{value
|
||||
|
@ -83,11 +83,7 @@ const SettingsContainer = ({
|
||||
const renderBody = () => (
|
||||
<>
|
||||
{!isMobileView && (
|
||||
<HideButton
|
||||
text={t("Settings:LDAP")}
|
||||
value={isSettingsShown}
|
||||
isDisabled={!isLdapAvailable}
|
||||
/>
|
||||
<HideButton text={t("Settings:LDAP")} value={isSettingsShown} />
|
||||
)}
|
||||
|
||||
{isMobileView && <ToggleLDAP />}
|
||||
|
@ -45,6 +45,7 @@ const SubmitResetButtons = (props) => {
|
||||
hasChanges,
|
||||
isLoadingXml,
|
||||
enableSso,
|
||||
isSSOAvailable,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
@ -62,7 +63,9 @@ const SubmitResetButtons = (props) => {
|
||||
saveButtonDisabled={
|
||||
!enableSso || hasErrors || !hasChanges || isLoadingXml
|
||||
}
|
||||
cancelEnable={!(isSubmitLoading || isLoadingXml)}
|
||||
disableRestoreToDefault={
|
||||
isSubmitLoading || isLoadingXml || !isSSOAvailable
|
||||
}
|
||||
additionalClassSaveButton="save-button"
|
||||
additionalClassCancelButton="restore-button"
|
||||
/>
|
||||
@ -71,7 +74,7 @@ const SubmitResetButtons = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ ssoStore }) => {
|
||||
export default inject(({ ssoStore, currentQuotaStore }) => {
|
||||
const {
|
||||
saveSsoSettings,
|
||||
isSsoEnabled,
|
||||
@ -84,6 +87,7 @@ export default inject(({ ssoStore }) => {
|
||||
isLoadingXml,
|
||||
enableSso,
|
||||
} = ssoStore;
|
||||
const { isSSOAvailable } = currentQuotaStore;
|
||||
|
||||
return {
|
||||
saveSsoSettings,
|
||||
@ -96,5 +100,6 @@ export default inject(({ ssoStore }) => {
|
||||
hasChanges,
|
||||
isLoadingXml,
|
||||
enableSso,
|
||||
isSSOAvailable,
|
||||
};
|
||||
})(observer(SubmitResetButtons));
|
||||
|
@ -69,7 +69,6 @@ const SingleSignOn = (props) => {
|
||||
<StyledSsoPage
|
||||
hideSettings={serviceProviderSettings}
|
||||
hideMetadata={spMetadata}
|
||||
isSettingPaid={isSSOAvailable}
|
||||
>
|
||||
<Text className="intro-text settings_unavailable" noSelect>
|
||||
{t("SsoIntro")}
|
||||
@ -88,7 +87,7 @@ const SingleSignOn = (props) => {
|
||||
})}
|
||||
label={SERVICE_PROVIDER_SETTINGS}
|
||||
value={serviceProviderSettings}
|
||||
isDisabled={!isSSOAvailable}
|
||||
//isDisabled={!isSSOAvailable}
|
||||
/>
|
||||
|
||||
<SPSettings />
|
||||
@ -101,7 +100,7 @@ const SingleSignOn = (props) => {
|
||||
})}
|
||||
label={SP_METADATA}
|
||||
value={spMetadata}
|
||||
isDisabled={!isSSOAvailable}
|
||||
//isDisabled={!isSSOAvailable}
|
||||
/>
|
||||
|
||||
<Box className="sp-metadata">
|
||||
|
@ -25,7 +25,6 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import styled, { css } from "styled-components";
|
||||
import { UnavailableStyles } from "../../../../utils/commonSettingsStyles";
|
||||
|
||||
const StyledSsoPage = styled.div`
|
||||
max-width: 100%;
|
||||
@ -147,8 +146,6 @@ const StyledSsoPage = styled.div`
|
||||
`}
|
||||
}
|
||||
}
|
||||
|
||||
${(props) => !props.isSettingPaid && UnavailableStyles}
|
||||
`;
|
||||
|
||||
export default StyledSsoPage;
|
||||
|
@ -52,22 +52,13 @@ const StyledWrapper = styled.div`
|
||||
|
||||
const HideButton = (props) => {
|
||||
const { t } = useTranslation("SingleSignOn");
|
||||
const {
|
||||
text,
|
||||
label,
|
||||
isAdditionalParameters,
|
||||
value,
|
||||
setHideLabel,
|
||||
isDisabled,
|
||||
id,
|
||||
} = props;
|
||||
const { text, label, isAdditionalParameters, value, setHideLabel, id } =
|
||||
props;
|
||||
|
||||
const onClick = () => {
|
||||
setHideLabel(label);
|
||||
};
|
||||
|
||||
const onClickProp = isDisabled ? {} : { onClick: onClick };
|
||||
|
||||
return (
|
||||
<StyledWrapper isAdditionalParameters={isAdditionalParameters}>
|
||||
{!isAdditionalParameters && (
|
||||
@ -86,7 +77,7 @@ const HideButton = (props) => {
|
||||
id={id}
|
||||
className="hide-button settings_unavailable"
|
||||
isHovered
|
||||
{...onClickProp}
|
||||
onClick={onClick}
|
||||
type="action"
|
||||
>
|
||||
{value
|
||||
|
@ -32,6 +32,7 @@ import { Text } from "@docspace/shared/components/text";
|
||||
import { ToggleButton } from "@docspace/shared/components/toggle-button";
|
||||
import { Badge } from "@docspace/shared/components/badge";
|
||||
import { mobile } from "@docspace/shared/utils";
|
||||
import { UnavailableStyles } from "../../../../utils/commonSettingsStyles";
|
||||
|
||||
const StyledWrapper = styled.div`
|
||||
display: flex;
|
||||
@ -69,6 +70,8 @@ const StyledWrapper = styled.div`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
${(props) => !props.isSSOAvailable && UnavailableStyles}
|
||||
`;
|
||||
|
||||
const ToggleSSO = ({ enableSso, ssoToggle, isSSOAvailable }) => {
|
||||
@ -76,7 +79,7 @@ const ToggleSSO = ({ enableSso, ssoToggle, isSSOAvailable }) => {
|
||||
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<StyledWrapper>
|
||||
<StyledWrapper isSSOAvailable={isSSOAvailable}>
|
||||
<ToggleButton
|
||||
className="enable-sso toggle"
|
||||
isChecked={enableSso}
|
||||
|
@ -279,7 +279,7 @@ class ConsumerModalDialog extends React.Component {
|
||||
>
|
||||
<ModalDialog.Header>{selectedConsumer.title}</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<Box paddingProp="0 0 16px">{consumerInstruction}</Box>
|
||||
<Box paddingProp="16px 0 16px">{consumerInstruction}</Box>
|
||||
<React.Fragment>
|
||||
{selectedConsumer.props.map((prop, i) =>
|
||||
this.inputsRender(prop, i),
|
||||
|
@ -70,7 +70,7 @@ export const StyledAvatarWrapper = styled.div`
|
||||
|
||||
@media ${mobile} {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
${(props) =>
|
||||
props.theme.interfaceDirection === "rtl"
|
||||
|
@ -70,6 +70,7 @@ export const StyledPage = styled.div`
|
||||
|
||||
.public-room-text {
|
||||
margin: 8px 0;
|
||||
white-space: wrap;
|
||||
}
|
||||
|
||||
.public-room-name {
|
||||
@ -83,12 +84,6 @@ export const StyledPage = styled.div`
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.public-room-text {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -294,6 +294,7 @@ const Sdk = ({
|
||||
acceptButtonLabel={frameConfig?.acceptButtonLabel}
|
||||
cancelButtonLabel={frameConfig?.cancelButtonLabel}
|
||||
currentFolderId={frameConfig?.id}
|
||||
openRoot={!frameConfig?.id}
|
||||
descriptionText={formatsDescription[frameConfig?.filterParam] || ""}
|
||||
/>
|
||||
);
|
||||
|
@ -28,7 +28,7 @@ import { makeAutoObservable } from "mobx";
|
||||
import { isMobile } from "@docspace/shared/utils";
|
||||
import { checkDialogsOpen } from "@docspace/shared/utils/checkDialogsOpen";
|
||||
import { TUser, TUserGroup } from "@docspace/shared/api/people/types";
|
||||
import { TABLE_HEADER_HEIGHT } from "@docspace/shared/components/table/Table.constants";
|
||||
import { TABLE_HEADER_HEIGHT } from "@docspace/shared/utils/device";
|
||||
|
||||
type AccountsType = TUser | TUserGroup;
|
||||
|
||||
|
@ -116,6 +116,13 @@ const LOADER_TIMER = 500;
|
||||
let loadingTime;
|
||||
let timer;
|
||||
|
||||
const systemFolders = [
|
||||
FolderType.InProgress,
|
||||
FolderType.Done,
|
||||
FolderType.SubFolderDone,
|
||||
FolderType.SubFolderInProgress,
|
||||
];
|
||||
|
||||
class ContextOptionsStore {
|
||||
settingsStore;
|
||||
dialogsStore;
|
||||
@ -409,7 +416,9 @@ class ContextOptionsStore {
|
||||
|
||||
const isShared = shared || sharedItem;
|
||||
|
||||
if (isShared && !isArchive) {
|
||||
const isSystemFolder = systemFolders.includes(item.type);
|
||||
|
||||
if (isShared && !isArchive && !isSystemFolder) {
|
||||
try {
|
||||
const itemLink = item.isFolder
|
||||
? await getFolderLink(item.id)
|
||||
@ -965,7 +974,7 @@ class ContextOptionsStore {
|
||||
const filterUrlParams = filesFilter.toUrlParams();
|
||||
const url = getCategoryUrl(
|
||||
this.filesStore.categoryType,
|
||||
filterUrlParams.folder,
|
||||
filesFilter.folder,
|
||||
);
|
||||
|
||||
navigate(
|
||||
|
@ -1723,6 +1723,8 @@ class FilesStore {
|
||||
].includes(err?.response?.status);
|
||||
|
||||
if (isUserError && !isThirdPartyError) {
|
||||
if (isPublicRoom()) return Promise.reject(err);
|
||||
|
||||
this.setIsErrorRoomNotAvailable(true);
|
||||
} else {
|
||||
if (axios.isCancel(err)) {
|
||||
@ -3961,19 +3963,6 @@ class FilesStore {
|
||||
|
||||
openDocEditor = (id, preview = false, shareKey = null, editForm = false) => {
|
||||
const { openOnNewPage } = this.filesSettingsStore;
|
||||
const foundIndex = this.files.findIndex((x) => x.id === id);
|
||||
const file = foundIndex !== -1 ? this.files[foundIndex] : undefined;
|
||||
if (
|
||||
file &&
|
||||
!preview &&
|
||||
file.rootFolderType !== FolderType.Archive &&
|
||||
file.fileExst !== ".oform"
|
||||
) {
|
||||
const newStatus = file.fileStatus | FileStatus.IsEditing;
|
||||
|
||||
this.updateSelectionStatus(id, newStatus, true);
|
||||
this.updateFileStatus(foundIndex, newStatus);
|
||||
}
|
||||
|
||||
const share = shareKey ? shareKey : this.publicRoomStore.publicRoomKey;
|
||||
|
||||
|
@ -37,7 +37,7 @@ import getFilesFromEvent from "@docspace/shared/components/drag-and-drop/get-fil
|
||||
import config from "PACKAGE_FILE";
|
||||
import { getCategoryUrl } from "SRC_DIR/helpers/utils";
|
||||
import { encryptionUploadDialog } from "../helpers/encryptionUploadDialog";
|
||||
import { TABLE_HEADER_HEIGHT } from "@docspace/shared/components/table/Table.constants";
|
||||
import { TABLE_HEADER_HEIGHT } from "@docspace/shared/utils/device";
|
||||
|
||||
class HotkeyStore {
|
||||
filesStore;
|
||||
|
@ -29,6 +29,7 @@ import { makeAutoObservable } from "mobx";
|
||||
|
||||
import api from "@docspace/shared/api";
|
||||
import FilesFilter from "@docspace/shared/api/files/filter";
|
||||
import { combineUrl } from "@docspace/shared/utils/combineUrl";
|
||||
import {
|
||||
frameCallCommand,
|
||||
isPublicRoom as isPublicRoomUtil,
|
||||
@ -124,7 +125,13 @@ class PublicRoomStore {
|
||||
|
||||
if (filter) {
|
||||
const folderId = filter.folder;
|
||||
return fetchFiles(folderId, filter);
|
||||
return fetchFiles(folderId, filter).catch((error) => {
|
||||
if (error?.response?.status === 403) {
|
||||
window.location.replace(
|
||||
combineUrl(window.ClientConfig?.proxy?.url, "/login"),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
|
@ -1,12 +1,12 @@
|
||||
{
|
||||
"BackToRoom": "Back to room",
|
||||
"CheckReadyForm": "Check ready form",
|
||||
"CheckReadyForms": "Check ready forms",
|
||||
"Description": "Your form completed and saved",
|
||||
"DescriptionForAnonymous": "You submitted the filled PDF form which was assigned a unique number. To check the status, contact the form owner providing the assigned number.",
|
||||
"DescriptionForRegisteredUser": "The filled PDF form is saved and available to you in the Complete folder. To check the status, contact the form owner providing the assigned number.",
|
||||
"FillItOutAgain": "Fill it out again",
|
||||
"FormCompletedSuccessfully": "Form completed successfully",
|
||||
"FormNumber": "Form number:",
|
||||
"Manager": "Manager:",
|
||||
"FormOwner": "Form owner",
|
||||
"Title": "The form is completed"
|
||||
}
|
||||
|
@ -24,15 +24,18 @@
|
||||
// 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 { redirect } from "next/navigation";
|
||||
import { headers } from "next/headers";
|
||||
import { headers, cookies } from "next/headers";
|
||||
|
||||
import { ThemeKeys } from "@docspace/shared/enums";
|
||||
import { getBaseUrl } from "@docspace/shared/utils/next-ssr-helper";
|
||||
import { SYSTEM_THEME_KEY } from "@docspace/shared/constants";
|
||||
|
||||
import Providers from "@/providers";
|
||||
import Scripts from "@/components/Scripts";
|
||||
import StyledComponentsRegistry from "@/utils/registry";
|
||||
import { getColorTheme, getSettings, getUser } from "@/utils/actions";
|
||||
|
||||
import "@/styles/globals.scss";
|
||||
import Providers from "@/providers";
|
||||
import { getSettings, getUser } from "@/utils/actions";
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
@ -41,13 +44,23 @@ export default async function RootLayout({
|
||||
}) {
|
||||
const hdrs = headers();
|
||||
|
||||
const cookieStore = cookies();
|
||||
|
||||
const systemTheme = cookieStore.get(SYSTEM_THEME_KEY)?.value as
|
||||
| ThemeKeys
|
||||
| undefined;
|
||||
|
||||
if (hdrs.get("x-health-check") || hdrs.get("referer")?.includes("/health")) {
|
||||
console.log("is health check");
|
||||
return <></>;
|
||||
}
|
||||
|
||||
const startDate = new Date();
|
||||
const [user, settings] = await Promise.all([getUser(), getSettings()]);
|
||||
const [user, settings, colorTheme] = await Promise.all([
|
||||
getUser(),
|
||||
getSettings(),
|
||||
getColorTheme(),
|
||||
]);
|
||||
const timer = new Date().getTime() - startDate.getTime();
|
||||
|
||||
if (settings === "access-restricted") redirect(`${getBaseUrl()}/${settings}`);
|
||||
@ -70,7 +83,7 @@ export default async function RootLayout({
|
||||
<body>
|
||||
<StyledComponentsRegistry>
|
||||
<Providers
|
||||
contextData={{ user, settings }}
|
||||
contextData={{ user, settings, systemTheme, colorTheme }}
|
||||
api_host={api_host}
|
||||
timer={timer}
|
||||
>
|
||||
|
@ -169,6 +169,7 @@ const Editor = ({
|
||||
goBack = {
|
||||
requestClose: true,
|
||||
text: openFileLocationText,
|
||||
blank: openOnNewPage,
|
||||
};
|
||||
} else {
|
||||
goBack = {
|
||||
|
@ -43,11 +43,9 @@ export const CompletedFormLayout = styled.section<CompletedFormLayoutProps>`
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
height: 100dvh;
|
||||
min-height: 100dvh;
|
||||
padding: 100px 16px 16px;
|
||||
|
||||
overflow-y: auto;
|
||||
|
||||
background-image: ${(props) => props.bgPattern};
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
@ -85,7 +83,7 @@ export const CompletedFormLayout = styled.section<CompletedFormLayoutProps>`
|
||||
align-self: center;
|
||||
justify-content: center;
|
||||
height: 48px;
|
||||
width: 100vw;
|
||||
width: calc(100% + 32px);
|
||||
margin: 0 -16px;
|
||||
|
||||
margin-bottom: 32px;
|
||||
@ -163,7 +161,7 @@ export const MainContent = styled.main`
|
||||
width: 100%;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
grid-template-columns: 45fr 101fr;
|
||||
grid-template-rows: 1fr auto;
|
||||
grid-template-areas:
|
||||
"form-file form-file form-file"
|
||||
@ -175,6 +173,10 @@ export const MainContent = styled.main`
|
||||
|
||||
.completed-form__file {
|
||||
grid-area: form-file;
|
||||
|
||||
svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.completed-form__filename {
|
||||
@ -182,11 +184,16 @@ export const MainContent = styled.main`
|
||||
line-height: 16px;
|
||||
|
||||
margin: 0px;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.completed-form__download {
|
||||
cursor: pointer;
|
||||
margin-inline-start: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
@ -204,6 +211,15 @@ export const MainContent = styled.main`
|
||||
font-weight: 600;
|
||||
color: ${(props) => props.theme.completedForm.descriptionColor};
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
grid-template-columns: 100%;
|
||||
|
||||
grid-template-areas:
|
||||
"form-file"
|
||||
"form-number"
|
||||
"manager";
|
||||
}
|
||||
`;
|
||||
|
||||
export const FormNumberWrapper = styled.div`
|
||||
@ -249,14 +265,49 @@ export const ManagerWrapper = styled.div`
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
font-weight: 700;
|
||||
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
/* max-width: 300px; */
|
||||
}
|
||||
|
||||
.manager__mail {
|
||||
grid-area: mail;
|
||||
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
svg {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media ${mobile} {
|
||||
grid-template-columns: 100%;
|
||||
grid-template-areas:
|
||||
"avatar"
|
||||
"user-name"
|
||||
"mail";
|
||||
|
||||
.manager__avatar {
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.manager__user-name {
|
||||
text-align: center;
|
||||
}
|
||||
.manager__mail {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -114,10 +114,17 @@ export const CompletedForm = ({
|
||||
);
|
||||
|
||||
const {
|
||||
response: { completedForm, formNumber, manager, originalForm, roomId },
|
||||
response: {
|
||||
completedForm,
|
||||
formNumber,
|
||||
manager,
|
||||
originalForm,
|
||||
roomId,
|
||||
isRoomMember,
|
||||
},
|
||||
} = session;
|
||||
|
||||
const isAnonim = Boolean(share);
|
||||
const isAnonim = Boolean(share) && !isRoomMember;
|
||||
|
||||
const getFolderUrl = (folderId: number, isAnonim: boolean): string => {
|
||||
if (isNullOrUndefined(folderId)) return "";
|
||||
@ -135,10 +142,6 @@ export const CompletedForm = ({
|
||||
return `${origin}${path}${filter.toUrlParams()}`;
|
||||
};
|
||||
|
||||
const setHistory = (url: string) => {
|
||||
history.pushState({}, "", url);
|
||||
};
|
||||
|
||||
const copyLinkFile = async () => {
|
||||
const origin = window.location.origin;
|
||||
|
||||
@ -154,14 +157,12 @@ export const CompletedForm = ({
|
||||
|
||||
const gotoCompleteFolder = () => {
|
||||
const url = getFolderUrl(completedForm.folderId, false);
|
||||
setHistory(url);
|
||||
window.location.replace(url);
|
||||
window.location.assign(url);
|
||||
};
|
||||
|
||||
const handleBackToRoom = () => {
|
||||
const url = getFolderUrl(roomId, isAnonim);
|
||||
setHistory(url);
|
||||
window.location.replace(url);
|
||||
window.location.assign(url);
|
||||
};
|
||||
|
||||
const fillAgainSearchParams = new URLSearchParams({
|
||||
@ -207,7 +208,7 @@ export const CompletedForm = ({
|
||||
</Box>
|
||||
</FormNumberWrapper>
|
||||
<ManagerWrapper>
|
||||
<span className="label">{t("CompletedForm:Manager")}</span>
|
||||
<span className="label">{t("CompletedForm:FormOwner")}</span>
|
||||
<Box>
|
||||
<Avatar
|
||||
className="manager__avatar"
|
||||
@ -223,22 +224,22 @@ export const CompletedForm = ({
|
||||
href={`mailto:${manager.email}`}
|
||||
>
|
||||
<MailIcon />
|
||||
{manager.email}
|
||||
<span>{manager.email}</span>
|
||||
</Link>
|
||||
</Box>
|
||||
</ManagerWrapper>
|
||||
</MainContent>
|
||||
<ButtonWrapper isShreFile={isShreFile}>
|
||||
<ButtonWrapper isShreFile={isShreFile && !isRoomMember}>
|
||||
<Button
|
||||
scale
|
||||
primary
|
||||
size={ButtonSize.medium}
|
||||
label={
|
||||
isAnonim ? t("Common:Download") : t("CompletedForm:CheckReadyForm")
|
||||
isAnonim ? t("Common:Download") : t("CompletedForm:CheckReadyForms")
|
||||
}
|
||||
onClick={isAnonim ? handleDownload : gotoCompleteFolder}
|
||||
/>
|
||||
{!isShreFile && (
|
||||
{(!isShreFile || isRoomMember) && (
|
||||
<Button
|
||||
scale
|
||||
size={ButtonSize.medium}
|
||||
|
@ -39,6 +39,7 @@ export type CompletedFormProps = {
|
||||
originalForm: TFile;
|
||||
formNumber: number;
|
||||
roomId: number;
|
||||
isRoomMember: boolean;
|
||||
};
|
||||
};
|
||||
isShreFile: boolean;
|
||||
|
@ -38,8 +38,11 @@ interface UseI18NProps {
|
||||
|
||||
const useI18N = ({ settings, user }: UseI18NProps) => {
|
||||
const [i18n, setI18N] = React.useState<i18n>(
|
||||
getI18NInstance(user?.cultureName ?? "en", settings?.culture ?? "en") ??
|
||||
({} as i18n),
|
||||
() =>
|
||||
getI18NInstance(
|
||||
user?.cultureName ?? settings?.culture ?? "en",
|
||||
settings?.culture ?? "en",
|
||||
) ?? ({} as i18n),
|
||||
);
|
||||
|
||||
const isInit = React.useRef(false);
|
||||
@ -53,7 +56,7 @@ const useI18N = ({ settings, user }: UseI18NProps) => {
|
||||
isInit.current = true;
|
||||
|
||||
const instance = getI18NInstance(
|
||||
user?.cultureName ?? "en",
|
||||
user?.cultureName ?? settings?.culture ?? "en",
|
||||
settings?.culture ?? "en",
|
||||
);
|
||||
|
||||
|
@ -34,7 +34,7 @@ import {
|
||||
} from "@docspace/shared/api/files";
|
||||
// import { getOperationProgress } from "@docspace/shared/utils/getOperationProgress";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
import { EDITOR_ID } from "@docspace/shared/constants";
|
||||
import { CREATED_FORM_KEY, EDITOR_ID } from "@docspace/shared/constants";
|
||||
|
||||
import type {
|
||||
TFile,
|
||||
@ -52,6 +52,13 @@ import type { TData } from "@docspace/shared/components/toast/Toast.type";
|
||||
import { saveAs } from "@/utils";
|
||||
import type { ConflictStateType } from "@/types";
|
||||
|
||||
type SuccessResponseType = {
|
||||
form: TFile;
|
||||
message: string;
|
||||
};
|
||||
type FaildResponseType = string;
|
||||
type ResponseType = SuccessResponseType | FaildResponseType;
|
||||
|
||||
const DefaultConflictDataDialogState: ConflictStateType = {
|
||||
visible: false,
|
||||
resolve: () => {},
|
||||
@ -70,6 +77,12 @@ const hasFileUrl = (arg: object): arg is { data: { url: string } } => {
|
||||
);
|
||||
};
|
||||
|
||||
const isSuccessResponse = (
|
||||
res: ResponseType | undefined,
|
||||
): res is SuccessResponseType => {
|
||||
return Boolean(res) && typeof res === "object" && "form" in res;
|
||||
};
|
||||
|
||||
const useStartFillingSelectDialog = (fileInfo: TFile | undefined) => {
|
||||
// const { t } = useTranslation(["Common"]);
|
||||
const resolveRef = useRef<(value: string | PromiseLike<string>) => void>();
|
||||
@ -179,14 +192,22 @@ const useStartFillingSelectDialog = (fileInfo: TFile | undefined) => {
|
||||
|
||||
const fileUrl = await getFileUrl();
|
||||
|
||||
const response = await saveAs(
|
||||
const response = await saveAs<ResponseType>(
|
||||
fileInfo.title,
|
||||
fileUrl,
|
||||
selectedItemId,
|
||||
false,
|
||||
"createForm",
|
||||
);
|
||||
|
||||
const [key, value] = response?.split(":") ?? [];
|
||||
if (isSuccessResponse(response)) {
|
||||
const { form } = response;
|
||||
|
||||
sessionStorage.setItem(CREATED_FORM_KEY, JSON.stringify(form));
|
||||
}
|
||||
|
||||
const [key, value] =
|
||||
typeof response === "string" ? response.split(":") : [];
|
||||
|
||||
// await copyToFolder(
|
||||
// Number(selectedItemId),
|
||||
|
@ -26,34 +26,64 @@
|
||||
|
||||
import React from "react";
|
||||
import { i18n } from "i18next";
|
||||
import { match, P } from "ts-pattern";
|
||||
|
||||
import { Base, Dark, TColorScheme, TTheme } from "@docspace/shared/themes";
|
||||
import { getSystemTheme } from "@docspace/shared/utils";
|
||||
import { setCookie } from "@docspace/shared/utils/cookie";
|
||||
import { ThemeKeys } from "@docspace/shared/enums";
|
||||
import { getAppearanceTheme } from "@docspace/shared/api/settings";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { getFontFamilyDependingOnLanguage } from "@docspace/shared/utils/rtlUtils";
|
||||
import { SYSTEM_THEME_KEY } from "@docspace/shared/constants";
|
||||
|
||||
const SYSTEM_THEME = getSystemTheme();
|
||||
import type { TUser } from "@docspace/shared/api/people/types";
|
||||
import type { TGetColorTheme } from "@docspace/shared/api/settings/types";
|
||||
|
||||
type MatchType = [ThemeKeys | undefined, ThemeKeys | undefined];
|
||||
|
||||
export interface UseThemeProps {
|
||||
user?: TUser;
|
||||
i18n?: i18n;
|
||||
systemTheme?: ThemeKeys;
|
||||
colorTheme?: TGetColorTheme;
|
||||
lang?: string;
|
||||
}
|
||||
|
||||
const useTheme = ({ user, i18n }: UseThemeProps) => {
|
||||
const useTheme = ({
|
||||
user,
|
||||
i18n,
|
||||
systemTheme,
|
||||
colorTheme,
|
||||
lang,
|
||||
}: UseThemeProps) => {
|
||||
const [currentColorTheme, setCurrentColorTheme] =
|
||||
React.useState<TColorScheme>({} as TColorScheme);
|
||||
React.useState<TColorScheme>(() => {
|
||||
if (!colorTheme) return {} as TColorScheme;
|
||||
|
||||
return (
|
||||
colorTheme.themes.find((theme) => theme.id === colorTheme.selected) ??
|
||||
({} as TColorScheme)
|
||||
);
|
||||
});
|
||||
|
||||
const [theme, setTheme] = React.useState<TTheme>(() => {
|
||||
if (user?.theme === ThemeKeys.DarkStr)
|
||||
return {
|
||||
...Dark,
|
||||
currentColorScheme: currentColorTheme,
|
||||
};
|
||||
const interfaceDirection = i18n?.dir ? i18n.dir(lang) : "ltr";
|
||||
|
||||
const newTheme = match<MatchType>([user?.theme, systemTheme])
|
||||
.returnType<TTheme>()
|
||||
.with([ThemeKeys.DarkStr, P._], () => Dark)
|
||||
.with([ThemeKeys.BaseStr, P._], () => Base)
|
||||
.with([ThemeKeys.SystemStr, ThemeKeys.BaseStr], () => Base)
|
||||
.with([ThemeKeys.SystemStr, ThemeKeys.DarkStr], () => Dark)
|
||||
.with([undefined, ThemeKeys.DarkStr], () => Dark)
|
||||
.with([undefined, ThemeKeys.BaseStr], () => Base)
|
||||
.otherwise(() => Base);
|
||||
|
||||
return {
|
||||
...Base,
|
||||
...newTheme,
|
||||
currentColorScheme: currentColorTheme,
|
||||
interfaceDirection,
|
||||
fontFamily: getFontFamilyDependingOnLanguage(i18n?.language ?? "en"),
|
||||
};
|
||||
});
|
||||
|
||||
@ -73,29 +103,27 @@ const useTheme = ({ user, i18n }: UseThemeProps) => {
|
||||
}, []);
|
||||
|
||||
const getUserTheme = React.useCallback(() => {
|
||||
if (!user?.theme) return;
|
||||
let theme = user.theme;
|
||||
const interfaceDirection = i18n?.dir ? i18n.dir() : "ltr";
|
||||
const SYSTEM_THEME = getSystemTheme();
|
||||
|
||||
if (user.theme === ThemeKeys.SystemStr) theme = SYSTEM_THEME;
|
||||
let theme = user?.theme ?? SYSTEM_THEME;
|
||||
const interfaceDirection = i18n?.dir ? i18n.dir(lang) : "ltr";
|
||||
|
||||
if (theme === ThemeKeys.BaseStr) {
|
||||
setTheme({
|
||||
...Base,
|
||||
currentColorScheme: currentColorTheme,
|
||||
interfaceDirection,
|
||||
fontFamily: getFontFamilyDependingOnLanguage(i18n?.language),
|
||||
});
|
||||
if (user?.theme === ThemeKeys.SystemStr) theme = SYSTEM_THEME;
|
||||
|
||||
return;
|
||||
}
|
||||
const fontFamily = getFontFamilyDependingOnLanguage(i18n?.language ?? "en");
|
||||
|
||||
const isBaseTheme = theme === ThemeKeys.BaseStr;
|
||||
const themeCookie = isBaseTheme ? ThemeKeys.BaseStr : ThemeKeys.DarkStr;
|
||||
|
||||
setTheme({
|
||||
...Dark,
|
||||
...(isBaseTheme ? Base : Dark),
|
||||
currentColorScheme: currentColorTheme,
|
||||
interfaceDirection,
|
||||
fontFamily,
|
||||
});
|
||||
}, [user?.theme, i18n, currentColorTheme]);
|
||||
|
||||
setCookie(SYSTEM_THEME_KEY, themeCookie);
|
||||
}, [user?.theme, i18n, currentColorTheme, lang]);
|
||||
|
||||
React.useEffect(() => {
|
||||
getCurrentColorTheme();
|
||||
@ -105,6 +133,16 @@ const useTheme = ({ user, i18n }: UseThemeProps) => {
|
||||
getUserTheme();
|
||||
}, [currentColorTheme, getUserTheme]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
mediaQuery.addEventListener("change", getUserTheme);
|
||||
|
||||
return () => {
|
||||
mediaQuery.removeEventListener("change", getUserTheme);
|
||||
};
|
||||
}, [getUserTheme]);
|
||||
|
||||
return { theme, currentColorTheme };
|
||||
};
|
||||
|
||||
|
@ -30,7 +30,11 @@ import React from "react";
|
||||
|
||||
import { ThemeProvider as ComponentThemeProvider } from "@docspace/shared/components/theme-provider";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
||||
import type {
|
||||
TGetColorTheme,
|
||||
TSettings,
|
||||
} from "@docspace/shared/api/settings/types";
|
||||
import type { ThemeKeys } from "@docspace/shared/enums";
|
||||
|
||||
import useTheme from "@/hooks/useTheme";
|
||||
import useI18N from "@/hooks/useI18N";
|
||||
@ -39,12 +43,28 @@ type TThemeProvider = {
|
||||
children: React.ReactNode;
|
||||
settings: TSettings | undefined;
|
||||
user: TUser | undefined;
|
||||
systemTheme: ThemeKeys | undefined;
|
||||
colorTheme: TGetColorTheme | undefined;
|
||||
};
|
||||
|
||||
const ThemeProvider = ({ children, user, settings }: TThemeProvider) => {
|
||||
const ThemeProvider = ({
|
||||
children,
|
||||
user,
|
||||
settings,
|
||||
systemTheme,
|
||||
colorTheme,
|
||||
}: TThemeProvider) => {
|
||||
const { i18n } = useI18N({ settings, user });
|
||||
|
||||
const { theme, currentColorTheme } = useTheme({ user, i18n });
|
||||
const lang = user?.cultureName ?? settings?.culture;
|
||||
|
||||
const { theme, currentColorTheme } = useTheme({
|
||||
user,
|
||||
i18n,
|
||||
systemTheme,
|
||||
colorTheme,
|
||||
lang,
|
||||
});
|
||||
|
||||
return (
|
||||
<ComponentThemeProvider
|
||||
|
@ -24,9 +24,13 @@
|
||||
// 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 { TUser } from "@docspace/shared/api/people/types";
|
||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
||||
import { Toast } from "@docspace/shared/components/toast/Toast";
|
||||
import type { TUser } from "@docspace/shared/api/people/types";
|
||||
import type {
|
||||
TGetColorTheme,
|
||||
TSettings,
|
||||
} from "@docspace/shared/api/settings/types";
|
||||
import type { ThemeKeys } from "@docspace/shared/enums";
|
||||
|
||||
import ThemeProvider from "./ThemeProvider";
|
||||
import TranslationProvider from "./TranslationProvider";
|
||||
@ -35,6 +39,8 @@ import ErrorProvider from "./ErrorProvider";
|
||||
export type TContextData = {
|
||||
user: TUser | undefined;
|
||||
settings: TSettings | undefined;
|
||||
systemTheme: ThemeKeys | undefined;
|
||||
colorTheme: TGetColorTheme | undefined;
|
||||
};
|
||||
|
||||
export type TProviders = {
|
||||
|
@ -36,7 +36,10 @@ import type {
|
||||
TFile,
|
||||
} from "@docspace/shared/api/files/types";
|
||||
import { TUser } from "@docspace/shared/api/people/types";
|
||||
import { TSettings } from "@docspace/shared/api/settings/types";
|
||||
import type {
|
||||
TGetColorTheme,
|
||||
TSettings,
|
||||
} from "@docspace/shared/api/settings/types";
|
||||
|
||||
import type {
|
||||
ActionType,
|
||||
@ -500,3 +503,19 @@ export async function getEditorUrl(
|
||||
|
||||
return editorUrl.response as TDocServiceLocation;
|
||||
}
|
||||
|
||||
export async function getColorTheme() {
|
||||
const [getSettings] = createRequest(
|
||||
[`/settings/colortheme`],
|
||||
[["", ""]],
|
||||
"GET",
|
||||
);
|
||||
|
||||
const res = await fetch(getSettings);
|
||||
|
||||
if (!res.ok) return;
|
||||
|
||||
const colorTheme = await res.json();
|
||||
|
||||
return colorTheme.response as TGetColorTheme;
|
||||
}
|
||||
|
@ -81,30 +81,31 @@ export const onSDKRequestEditRights = async (
|
||||
const url = window.location.href;
|
||||
const isPDF = documentType === "pdf";
|
||||
|
||||
if (isPDF) {
|
||||
const newURL = new URL(url);
|
||||
let newURL = new URL(url);
|
||||
|
||||
if (newURL.searchParams.has("action")) {
|
||||
newURL.searchParams.delete("action");
|
||||
if (
|
||||
!isPDF &&
|
||||
fileInfo?.viewAccessibility?.MustConvert &&
|
||||
fileInfo?.security?.Convert
|
||||
) {
|
||||
try {
|
||||
const response = await convertDocumentUrl(fileInfo.id);
|
||||
if (response && response.webUrl) {
|
||||
newURL = new URL(response.webUrl);
|
||||
} else {
|
||||
throw new Error("Invalid response data");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error converting document", { error });
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (newURL.searchParams.has("action")) newURL.searchParams.delete("action");
|
||||
|
||||
newURL.searchParams.append("action", "edit");
|
||||
|
||||
history.pushState({}, "", newURL.toString());
|
||||
document.location.reload();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let convertUrl = url;
|
||||
|
||||
if (fileInfo?.viewAccessibility?.MustConvert && fileInfo?.security?.Convert) {
|
||||
const newUrl = await convertDocumentUrl(fileInfo.id);
|
||||
if (newUrl) {
|
||||
convertUrl = newUrl.webUrl;
|
||||
}
|
||||
}
|
||||
history.pushState({}, "", convertUrl);
|
||||
history.pushState({}, "", newURL.toString());
|
||||
document.location.reload();
|
||||
};
|
||||
|
||||
|
@ -48,6 +48,8 @@ export const getBackUrl = (
|
||||
} else {
|
||||
backUrl = `/rooms/shared/${folderId}/filter?folder=${folderId}`;
|
||||
}
|
||||
} else if (rootFolderType === FolderType.Archive) {
|
||||
backUrl = `/rooms/archived/${folderId}/filter?folder=${folderId}`;
|
||||
} else {
|
||||
if (
|
||||
rootFolderType === FolderType.SHARE ||
|
||||
@ -99,14 +101,15 @@ export const getDataSaveAs = async (params: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const saveAs = (
|
||||
export const saveAs = <T = string>(
|
||||
title: string,
|
||||
url: string,
|
||||
folderId: string | number,
|
||||
openNewTab: boolean,
|
||||
action = "create",
|
||||
) => {
|
||||
const options = {
|
||||
action: "create",
|
||||
action,
|
||||
fileuri: url,
|
||||
title: title,
|
||||
folderid: folderId,
|
||||
@ -115,7 +118,7 @@ export const saveAs = (
|
||||
|
||||
const params = toUrlParams(options, true);
|
||||
if (!openNewTab) {
|
||||
return getDataSaveAs(params);
|
||||
return getDataSaveAs(params) as Promise<T>;
|
||||
} else {
|
||||
const handlerUrl = combineUrl(
|
||||
window.ClientConfig?.proxy?.url,
|
||||
|
@ -42,7 +42,10 @@ import { useSearchParams, useRouter } from "next/navigation";
|
||||
|
||||
import { Text } from "@docspace/shared/components/text";
|
||||
import { Button, ButtonSize } from "@docspace/shared/components/button";
|
||||
import { createPasswordHash } from "@docspace/shared/utils/common";
|
||||
import {
|
||||
createPasswordHash,
|
||||
frameCallCommand,
|
||||
} from "@docspace/shared/utils/common";
|
||||
import { checkPwd } from "@docspace/shared/utils/desktop";
|
||||
import { login } from "@docspace/shared/utils/loginUtils";
|
||||
import { toastr } from "@docspace/shared/components/toast";
|
||||
@ -129,6 +132,7 @@ const LoginForm = ({
|
||||
|
||||
setIdentifier(email);
|
||||
setEmailFromInvitation(email);
|
||||
frameCallCommand("setIsLoaded");
|
||||
}, [loginData]);
|
||||
|
||||
const authCallback = useCallback(
|
||||
|
@ -27,8 +27,12 @@
|
||||
import Filter from "./filter";
|
||||
|
||||
import { request } from "../client";
|
||||
import { checkFilterInstance } from "../../utils/common";
|
||||
import { TGroup } from "./types";
|
||||
import { checkFilterInstance, toUrlParams } from "../../utils/common";
|
||||
import {
|
||||
TGetGroupMembersInRoom,
|
||||
TGetGroupMembersInRoomFilter,
|
||||
TGroup,
|
||||
} from "./types";
|
||||
|
||||
// * Create
|
||||
|
||||
@ -104,11 +108,14 @@ export const getGroupsByUserId = (userId: string) => {
|
||||
export const getGroupMembersInRoom = (
|
||||
folderId: string | number,
|
||||
groupId: string,
|
||||
filter: TGetGroupMembersInRoomFilter,
|
||||
) => {
|
||||
const url = `/files/folder/${folderId}/group/${groupId}/share?${toUrlParams(filter, false)}`;
|
||||
|
||||
return request({
|
||||
method: "get",
|
||||
url: `/files/folder/${folderId}/group/${groupId}/share`,
|
||||
});
|
||||
url,
|
||||
}) as Promise<TGetGroupMembersInRoom>;
|
||||
};
|
||||
|
||||
// * Update
|
||||
|
@ -25,6 +25,7 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
import { TUser } from "../people/types";
|
||||
import { ShareAccessRights } from "../../enums";
|
||||
|
||||
export type TGroup = {
|
||||
category: string;
|
||||
@ -37,3 +38,23 @@ export type TGroup = {
|
||||
shared?: boolean;
|
||||
isLDAP: boolean;
|
||||
};
|
||||
|
||||
export type TGroupMemberInvitedInRoom = {
|
||||
user: TUser;
|
||||
canEditAccess: boolean;
|
||||
overridden: boolean;
|
||||
owner: boolean;
|
||||
groupAccess: number;
|
||||
userAccess: ShareAccessRights;
|
||||
};
|
||||
|
||||
export type TGetGroupMembersInRoom = {
|
||||
items: TGroupMemberInvitedInRoom[];
|
||||
total: number;
|
||||
};
|
||||
|
||||
export type TGetGroupMembersInRoomFilter = {
|
||||
startIndex?: number;
|
||||
count?: number;
|
||||
filterValue?: string;
|
||||
};
|
||||
|
@ -112,11 +112,11 @@ const StyledBody = styled.div<{
|
||||
height: ${(props) =>
|
||||
props.footerVisible
|
||||
? props.withHeader
|
||||
? `calc(100% - 16px - ${props.footerHeight}px - ${props.headerHeight}px)`
|
||||
: `calc(100% - 16px - ${props.footerHeight}px)`
|
||||
? `calc(100% - ${props.footerHeight}px - ${props.headerHeight}px)`
|
||||
: `calc(100% - ${props.footerHeight}px)`
|
||||
: props.withHeader
|
||||
? `calc(100% - 16px - ${props.headerHeight}px)`
|
||||
: `calc(100% - 16px)`};
|
||||
? `calc(100% - ${props.headerHeight}px)`
|
||||
: "100%"};
|
||||
|
||||
padding: ${({ withTabs }) => (withTabs ? "0" : "16px 0 0 0")};
|
||||
|
||||
|
@ -189,7 +189,7 @@ const Body = ({
|
||||
if (withInfoBar) {
|
||||
const infoEl = document.querySelector(".selector_info-bar");
|
||||
if (infoEl) {
|
||||
const height = infoEl.getClientRects()[0].height;
|
||||
const height = infoEl.getClientRects()[0].height + CONTAINER_PADDING;
|
||||
listHeight -= height;
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,10 @@
|
||||
// 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 { SETTINGS_SIZE } from "./Table.constants";
|
||||
export const MIN_SIZE_FIRST_COLUMN = 210;
|
||||
export const DEFAULT_MIN_COLUMN_SIZE = 110;
|
||||
export const SETTINGS_SIZE = 24;
|
||||
export const HANDLE_OFFSET = 8;
|
||||
|
||||
export const getSubstring = (str: string) => +str.substring(0, str.length - 2);
|
||||
|
||||
|
@ -38,16 +38,17 @@ import {
|
||||
import { TTableColumn, TableHeaderProps } from "./Table.types";
|
||||
import { TableSettings } from "./sub-components/TableSettings";
|
||||
import { TableHeaderCell } from "./sub-components/TableHeaderCell";
|
||||
import { checkingForUnfixedSize, getSubstring } from "./Table.utils";
|
||||
import {
|
||||
DEFAULT_MIN_COLUMN_SIZE,
|
||||
MIN_SIZE_FIRST_COLUMN,
|
||||
SETTINGS_SIZE,
|
||||
HANDLE_OFFSET,
|
||||
checkingForUnfixedSize,
|
||||
getSubstring,
|
||||
} from "./Table.utils";
|
||||
import { isDesktop } from "../../utils";
|
||||
|
||||
const defaultMinColumnSize = 110;
|
||||
const settingsSize = 24;
|
||||
|
||||
const minSizeFirstColumn = 210;
|
||||
const handleOffset = 8;
|
||||
|
||||
class TableHeader extends React.Component<
|
||||
class TableHeaderComponent extends React.Component<
|
||||
TableHeaderProps,
|
||||
{ hideColumns: boolean; columnIndex: null | number }
|
||||
> {
|
||||
@ -137,7 +138,7 @@ class TableHeader extends React.Component<
|
||||
if (leftColumn) {
|
||||
const minSize = leftColumn.dataset.minWidth
|
||||
? leftColumn.dataset.minWidth
|
||||
: defaultMinColumnSize;
|
||||
: DEFAULT_MIN_COLUMN_SIZE;
|
||||
|
||||
if (leftColumn.getBoundingClientRect().width <= +minSize) {
|
||||
if (colIndex < 0) return false;
|
||||
@ -185,17 +186,17 @@ class TableHeader extends React.Component<
|
||||
const defaultColumn = document.getElementById(`column_${colIndex}`);
|
||||
if (!defaultColumn || defaultColumn.dataset.defaultSize) return;
|
||||
|
||||
if (column2Width + offset - handleOffset >= defaultMinColumnSize) {
|
||||
widths[+columnIndex] = `${newWidth + handleOffset}px`;
|
||||
widths[colIndex] = `${column2Width + offset - handleOffset}px`;
|
||||
} else if (column2Width !== defaultMinColumnSize) {
|
||||
if (column2Width + offset - HANDLE_OFFSET >= DEFAULT_MIN_COLUMN_SIZE) {
|
||||
widths[+columnIndex] = `${newWidth + HANDLE_OFFSET}px`;
|
||||
widths[colIndex] = `${column2Width + offset - HANDLE_OFFSET}px`;
|
||||
} else if (column2Width !== DEFAULT_MIN_COLUMN_SIZE) {
|
||||
const width =
|
||||
getSubstring(widths[+columnIndex]) +
|
||||
getSubstring(widths[+colIndex]) -
|
||||
defaultMinColumnSize;
|
||||
DEFAULT_MIN_COLUMN_SIZE;
|
||||
|
||||
widths[+columnIndex] = `${width}px`;
|
||||
widths[colIndex] = `${defaultMinColumnSize}px`;
|
||||
widths[colIndex] = `${DEFAULT_MIN_COLUMN_SIZE}px`;
|
||||
} else {
|
||||
if (colIndex === columns.length) return false;
|
||||
this.moveToRight(widths, newWidth, colIndex + 1);
|
||||
@ -229,7 +230,7 @@ class TableHeader extends React.Component<
|
||||
)?.defaultSize;
|
||||
|
||||
const widthColumns =
|
||||
containerWidth - settingsSize - (defaultSizeColumn || 0);
|
||||
containerWidth - SETTINGS_SIZE - (defaultSizeColumn || 0);
|
||||
|
||||
const newColumnSize = defaultSize || widthColumns / allColumnsLength;
|
||||
|
||||
@ -247,9 +248,9 @@ class TableHeader extends React.Component<
|
||||
};
|
||||
|
||||
if (
|
||||
(indexOfMaxSize === 0 && newSizeMaxColumn < minSizeFirstColumn) ||
|
||||
(indexOfMaxSize !== 0 && newSizeMaxColumn < defaultMinColumnSize) ||
|
||||
newColumnSize < defaultMinColumnSize ||
|
||||
(indexOfMaxSize === 0 && newSizeMaxColumn < MIN_SIZE_FIRST_COLUMN) ||
|
||||
(indexOfMaxSize !== 0 && newSizeMaxColumn < DEFAULT_MIN_COLUMN_SIZE) ||
|
||||
newColumnSize < DEFAULT_MIN_COLUMN_SIZE ||
|
||||
enableColumnsLength === 1
|
||||
)
|
||||
return ResetColumnsSize();
|
||||
@ -277,14 +278,14 @@ class TableHeader extends React.Component<
|
||||
|
||||
const minSize = column.dataset.minWidth
|
||||
? column.dataset.minWidth
|
||||
: defaultMinColumnSize;
|
||||
: DEFAULT_MIN_COLUMN_SIZE;
|
||||
|
||||
if (newWidth <= +minSize - handleOffset) {
|
||||
if (newWidth <= +minSize - HANDLE_OFFSET) {
|
||||
const currentWidth = getSubstring(widths[+columnIndex]);
|
||||
|
||||
// Move left
|
||||
if (currentWidth !== +minSize) {
|
||||
newWidth = +minSize - handleOffset;
|
||||
newWidth = +minSize - HANDLE_OFFSET;
|
||||
this.moveToRight(widths, newWidth);
|
||||
} else this.moveToLeft(widths, newWidth);
|
||||
} else {
|
||||
@ -369,7 +370,7 @@ class TableHeader extends React.Component<
|
||||
if (storageSize) {
|
||||
const splitStorage = storageSize.split(" ");
|
||||
|
||||
if (getSubstring(splitStorage[0]) <= defaultMinColumnSize) {
|
||||
if (getSubstring(splitStorage[0]) <= DEFAULT_MIN_COLUMN_SIZE) {
|
||||
localStorage.removeItem(columnStorageName);
|
||||
this.onResize();
|
||||
return;
|
||||
@ -407,7 +408,7 @@ class TableHeader extends React.Component<
|
||||
.map((column) => getSubstring(column))
|
||||
.reduce((x, y) => x + y);
|
||||
|
||||
const oldWidth = defaultWidth - defaultSize - settingsSize;
|
||||
const oldWidth = defaultWidth - defaultSize - SETTINGS_SIZE;
|
||||
|
||||
let str = "";
|
||||
let gridTemplateColumnsWithoutOverfilling: string[] = [];
|
||||
@ -424,7 +425,7 @@ class TableHeader extends React.Component<
|
||||
? storageInfoPanelSize.split(" ")
|
||||
: tableContainer;
|
||||
|
||||
let containerMinWidth = containerWidth - defaultSize - settingsSize;
|
||||
let containerMinWidth = containerWidth - defaultSize - SETTINGS_SIZE;
|
||||
|
||||
tableInfoPanelContainer.forEach((item, index) => {
|
||||
const column = document.getElementById(`column_${index}`);
|
||||
@ -436,12 +437,12 @@ class TableHeader extends React.Component<
|
||||
if (
|
||||
enable &&
|
||||
(item !== `${defaultSize}px` || `${defaultSize}px` === `0px`) &&
|
||||
item !== `${settingsSize}px`
|
||||
item !== `${SETTINGS_SIZE}px`
|
||||
) {
|
||||
if (column?.dataset?.minWidth) {
|
||||
containerMinWidth -= +column.dataset.minWidth;
|
||||
} else {
|
||||
containerMinWidth -= defaultMinColumnSize;
|
||||
containerMinWidth -= DEFAULT_MIN_COLUMN_SIZE;
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -461,11 +462,11 @@ class TableHeader extends React.Component<
|
||||
|
||||
if (column?.dataset?.minWidth && column?.dataset?.default) {
|
||||
gridTemplateColumns.push(
|
||||
`${containerWidth - defaultSize - settingsSize}px`,
|
||||
`${containerWidth - defaultSize - SETTINGS_SIZE}px`,
|
||||
);
|
||||
} else if (
|
||||
item === `${defaultSize}px` ||
|
||||
item === `${settingsSize}px`
|
||||
item === `${SETTINGS_SIZE}px`
|
||||
) {
|
||||
gridTemplateColumns.push(item);
|
||||
} else {
|
||||
@ -477,7 +478,7 @@ class TableHeader extends React.Component<
|
||||
let hasGridTemplateColumnsWithoutOverfilling = false;
|
||||
if (infoPanelVisible) {
|
||||
if (!hideColumns) {
|
||||
const contentWidth = containerWidth - defaultSize - settingsSize;
|
||||
const contentWidth = containerWidth - defaultSize - SETTINGS_SIZE;
|
||||
|
||||
let enabledColumnsCount = 0;
|
||||
|
||||
@ -486,7 +487,7 @@ class TableHeader extends React.Component<
|
||||
index !== 0 &&
|
||||
item !== "0px" &&
|
||||
item !== `${defaultSize}px` &&
|
||||
item !== `${settingsSize}px`
|
||||
item !== `${SETTINGS_SIZE}px`
|
||||
) {
|
||||
enabledColumnsCount += 1;
|
||||
}
|
||||
@ -497,10 +498,10 @@ class TableHeader extends React.Component<
|
||||
.map((column) => getSubstring(column))
|
||||
.reduce((x, y) => x + y) -
|
||||
defaultSize -
|
||||
settingsSize;
|
||||
SETTINGS_SIZE;
|
||||
|
||||
if (
|
||||
contentWidth - enabledColumnsCount * defaultMinColumnSize >
|
||||
contentWidth - enabledColumnsCount * DEFAULT_MIN_COLUMN_SIZE >
|
||||
getSubstring(tableInfoPanelContainer[0])
|
||||
) {
|
||||
const currentContentWidth =
|
||||
@ -524,7 +525,7 @@ class TableHeader extends React.Component<
|
||||
|
||||
if (!enable) {
|
||||
gridTemplateColumns.push("0px");
|
||||
} else if (item !== `${settingsSize}px`) {
|
||||
} else if (item !== `${SETTINGS_SIZE}px`) {
|
||||
const percent =
|
||||
enabledColumnsCount === 0
|
||||
? 100
|
||||
@ -536,17 +537,17 @@ class TableHeader extends React.Component<
|
||||
const newItemWidth = defaultColumnSize
|
||||
? `${defaultColumnSize}px`
|
||||
: (currentContentWidth * percent) / 100 >
|
||||
defaultMinColumnSize
|
||||
DEFAULT_MIN_COLUMN_SIZE
|
||||
? `${(currentContentWidth * percent) / 100}px`
|
||||
: `${defaultMinColumnSize}px`;
|
||||
: `${DEFAULT_MIN_COLUMN_SIZE}px`;
|
||||
|
||||
if (
|
||||
(currentContentWidth * percent) / 100 <
|
||||
defaultMinColumnSize &&
|
||||
DEFAULT_MIN_COLUMN_SIZE &&
|
||||
!defaultColumnSize
|
||||
) {
|
||||
overWidth +=
|
||||
defaultMinColumnSize -
|
||||
DEFAULT_MIN_COLUMN_SIZE -
|
||||
(currentContentWidth * percent) / 100;
|
||||
}
|
||||
|
||||
@ -565,10 +566,10 @@ class TableHeader extends React.Component<
|
||||
index !== 0 &&
|
||||
column !== "0px" &&
|
||||
column !== `${defaultSize}px` &&
|
||||
column !== `${settingsSize}px` &&
|
||||
columnWidth > defaultMinColumnSize
|
||||
column !== `${SETTINGS_SIZE}px` &&
|
||||
columnWidth > DEFAULT_MIN_COLUMN_SIZE
|
||||
) {
|
||||
const availableWidth = columnWidth - defaultMinColumnSize;
|
||||
const availableWidth = columnWidth - DEFAULT_MIN_COLUMN_SIZE;
|
||||
|
||||
if (availableWidth < Math.abs(overWidth)) {
|
||||
overWidth = Math.abs(overWidth) - availableWidth;
|
||||
@ -598,15 +599,15 @@ class TableHeader extends React.Component<
|
||||
|
||||
if (!enable) {
|
||||
gridTemplateColumns.push("0px");
|
||||
} else if (item !== `${settingsSize}px`) {
|
||||
} else if (item !== `${SETTINGS_SIZE}px`) {
|
||||
const newItemWidth = defaultColumnSize
|
||||
? `${defaultColumnSize}px`
|
||||
: index === 0
|
||||
? `${
|
||||
contentWidth -
|
||||
enabledColumnsCount * defaultMinColumnSize
|
||||
enabledColumnsCount * DEFAULT_MIN_COLUMN_SIZE
|
||||
}px`
|
||||
: `${defaultMinColumnSize}px`;
|
||||
: `${DEFAULT_MIN_COLUMN_SIZE}px`;
|
||||
|
||||
gridTemplateColumns.push(newItemWidth);
|
||||
} else {
|
||||
@ -617,7 +618,7 @@ class TableHeader extends React.Component<
|
||||
}
|
||||
} else {
|
||||
let overWidth = 0;
|
||||
if (!hideColumns) {
|
||||
if (!hideColumns && !hideColumnsConst) {
|
||||
// eslint-disable-next-line guard-for-in, no-restricted-syntax
|
||||
for (const index in tableContainer) {
|
||||
const item = tableContainer[index];
|
||||
@ -646,7 +647,7 @@ class TableHeader extends React.Component<
|
||||
getSubstring(gridTemplateColumns[+index - colIndex]) +
|
||||
getSubstring(item)
|
||||
}px`;
|
||||
} else if (item !== `${settingsSize}px`) {
|
||||
} else if (item !== `${SETTINGS_SIZE}px`) {
|
||||
const percent = (getSubstring(item) / oldWidth) * 100;
|
||||
|
||||
if (percent === 100) {
|
||||
@ -663,30 +664,31 @@ class TableHeader extends React.Component<
|
||||
let newItemWidth = defaultColumnSize
|
||||
? `${defaultColumnSize}px`
|
||||
: percent === 0
|
||||
? `${defaultMinColumnSize}px`
|
||||
? `${DEFAULT_MIN_COLUMN_SIZE}px`
|
||||
: `${
|
||||
((containerWidth - defaultSize - settingsSize) *
|
||||
((containerWidth - defaultSize - SETTINGS_SIZE) *
|
||||
percent) /
|
||||
100
|
||||
}px`;
|
||||
|
||||
const minWidth = column?.dataset?.minWidth;
|
||||
const minSize = minWidth ? +minWidth : minSizeFirstColumn;
|
||||
const minSize = minWidth ? +minWidth : MIN_SIZE_FIRST_COLUMN;
|
||||
|
||||
// Checking whether the first column is less than the minimum width
|
||||
if (+index === 0 && getSubstring(newItemWidth) < minSize) {
|
||||
overWidth += minSizeFirstColumn - getSubstring(newItemWidth);
|
||||
newItemWidth = `${minSizeFirstColumn}px`;
|
||||
overWidth += MIN_SIZE_FIRST_COLUMN - getSubstring(newItemWidth);
|
||||
newItemWidth = `${MIN_SIZE_FIRST_COLUMN}px`;
|
||||
}
|
||||
|
||||
// Checking whether columns are smaller than the minimum width
|
||||
if (
|
||||
+index !== 0 &&
|
||||
!defaultColumnSize &&
|
||||
getSubstring(newItemWidth) < defaultMinColumnSize
|
||||
getSubstring(newItemWidth) < DEFAULT_MIN_COLUMN_SIZE
|
||||
) {
|
||||
overWidth += defaultMinColumnSize - getSubstring(newItemWidth);
|
||||
newItemWidth = `${defaultMinColumnSize}px`;
|
||||
overWidth +=
|
||||
DEFAULT_MIN_COLUMN_SIZE - getSubstring(newItemWidth);
|
||||
newItemWidth = `${DEFAULT_MIN_COLUMN_SIZE}px`;
|
||||
}
|
||||
|
||||
gridTemplateColumns.push(newItemWidth);
|
||||
@ -783,9 +785,11 @@ class TableHeader extends React.Component<
|
||||
|
||||
const column = document.getElementById(`column_${index}`);
|
||||
const minWidth = column?.dataset?.minWidth;
|
||||
const minSize = minWidth ? +minWidth : minSizeFirstColumn;
|
||||
const minSize = minWidth ? +minWidth : MIN_SIZE_FIRST_COLUMN;
|
||||
|
||||
if ((index === 0 ? minSize : defaultMinColumnSize) !== getSubstring(item))
|
||||
if (
|
||||
(index === 0 ? minSize : DEFAULT_MIN_COLUMN_SIZE) !== getSubstring(item)
|
||||
)
|
||||
countColumns += 1;
|
||||
});
|
||||
|
||||
@ -797,21 +801,21 @@ class TableHeader extends React.Component<
|
||||
|
||||
const column = document.getElementById(`column_${index}`);
|
||||
const minWidth = column?.dataset?.minWidth;
|
||||
const minSize = minWidth ? +minWidth : minSizeFirstColumn;
|
||||
const minSize = minWidth ? +minWidth : MIN_SIZE_FIRST_COLUMN;
|
||||
|
||||
const itemSubstring = getSubstring(item);
|
||||
|
||||
if ((index === 0 ? minSize : defaultMinColumnSize) === itemSubstring)
|
||||
if ((index === 0 ? minSize : DEFAULT_MIN_COLUMN_SIZE) === itemSubstring)
|
||||
return;
|
||||
|
||||
const differenceWithMinimum =
|
||||
itemSubstring - (index === 0 ? minSize : defaultMinColumnSize);
|
||||
itemSubstring - (index === 0 ? minSize : DEFAULT_MIN_COLUMN_SIZE);
|
||||
|
||||
if (differenceWithMinimum >= addWidth) {
|
||||
newGridTemplateColumns[index] = `${itemSubstring - addWidth}px`;
|
||||
} else {
|
||||
newGridTemplateColumns[index] = `${
|
||||
index === 0 ? minSize : defaultMinColumnSize
|
||||
index === 0 ? minSize : DEFAULT_MIN_COLUMN_SIZE
|
||||
}px`;
|
||||
}
|
||||
});
|
||||
@ -862,7 +866,7 @@ class TableHeader extends React.Component<
|
||||
columns.find((col) => col.defaultSize && col.enable)?.defaultSize || 0;
|
||||
|
||||
const containerWidth =
|
||||
container.clientWidth - defaultColumnSize - settingsSize;
|
||||
container.clientWidth - defaultColumnSize - SETTINGS_SIZE;
|
||||
|
||||
const firstColumnPercent = enableColumns.length > 0 ? 40 : 100;
|
||||
const percent = enableColumns.length > 0 ? 60 / enableColumns.length : 0;
|
||||
@ -882,7 +886,7 @@ class TableHeader extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
str += `${settingsSize}px`;
|
||||
str += `${SETTINGS_SIZE}px`;
|
||||
|
||||
if (container) container.style.gridTemplateColumns = str;
|
||||
if (this.headerRef && this.headerRef.current) {
|
||||
@ -970,4 +974,6 @@ class TableHeader extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
export default withTheme(TableHeader);
|
||||
const TableHeader = withTheme(TableHeaderComponent);
|
||||
|
||||
export { TableHeader };
|
||||
|
@ -24,13 +24,10 @@
|
||||
// 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 TableHeader from "./TableHeader";
|
||||
|
||||
export { TableHeader };
|
||||
export { TableContainer } from "./TableContainer";
|
||||
export { TableBody } from "./TableBody";
|
||||
export { TableRow } from "./TableRow";
|
||||
// export { TableHeader } from "./TableHeader";
|
||||
export { TableHeader } from "./TableHeader";
|
||||
export { TableGroupMenu } from "./TableGroupMenu";
|
||||
export { TableCell } from "./sub-components/TableCell";
|
||||
|
||||
|
@ -53,6 +53,7 @@ export const ROOM = "room";
|
||||
export const USERS = "users";
|
||||
export const USERS_IN_ROOM = "usersInRoom";
|
||||
export const PDF_FORM_DIALOG_KEY = "pdf_form_dialog";
|
||||
export const CREATED_FORM_KEY = "created_form_key";
|
||||
|
||||
export const COUNT_FOR_SHOWING_BAR = 2;
|
||||
export const PERCENTAGE_FOR_SHOWING_BAR = 90;
|
||||
|
@ -33,6 +33,30 @@ import {
|
||||
StyledMembersLoader,
|
||||
} from "../body.styled";
|
||||
|
||||
export const MemberLoader = ({ count = 1 }: { count?: number }) => {
|
||||
return (
|
||||
<>
|
||||
{[...Array(count).keys()].map((i) => (
|
||||
<StyledMemberLoader key={i}>
|
||||
<RectangleSkeleton
|
||||
className="avatar"
|
||||
width="32px"
|
||||
height="32px"
|
||||
borderRadius="50%"
|
||||
/>
|
||||
<RectangleSkeleton width="212px" height="16px" borderRadius="3px" />
|
||||
<RectangleSkeleton
|
||||
className="role-selector"
|
||||
width="64px"
|
||||
height="20px"
|
||||
borderRadius="3px"
|
||||
/>
|
||||
</StyledMemberLoader>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const MembersLoader = () => {
|
||||
return (
|
||||
<StyledMembersLoader>
|
||||
@ -41,46 +65,14 @@ const MembersLoader = () => {
|
||||
<RectangleSkeleton width="16px" height="16px" borderRadius="3px" />
|
||||
</StyledMemberSubtitleLoader>
|
||||
|
||||
{[...Array(4).keys()].map((i) => (
|
||||
<StyledMemberLoader key={i}>
|
||||
<RectangleSkeleton
|
||||
className="avatar"
|
||||
width="32px"
|
||||
height="32px"
|
||||
borderRadius="50%"
|
||||
/>
|
||||
<RectangleSkeleton width="212px" height="16px" borderRadius="3px" />
|
||||
<RectangleSkeleton
|
||||
className="role-selector"
|
||||
width="64px"
|
||||
height="20px"
|
||||
borderRadius="3px"
|
||||
/>
|
||||
</StyledMemberLoader>
|
||||
))}
|
||||
<MemberLoader count={4} />
|
||||
|
||||
<StyledMemberSubtitleLoader className="pending_users">
|
||||
<RectangleSkeleton width="111px" height="16px" borderRadius="3px" />
|
||||
<RectangleSkeleton width="16px" height="16px" borderRadius="3px" />
|
||||
</StyledMemberSubtitleLoader>
|
||||
|
||||
{[...Array(4).keys()].map((i) => (
|
||||
<StyledMemberLoader key={i}>
|
||||
<RectangleSkeleton
|
||||
className="avatar"
|
||||
width="32px"
|
||||
height="32px"
|
||||
borderRadius="50%"
|
||||
/>
|
||||
<RectangleSkeleton width="212px" height="16px" borderRadius="3px" />
|
||||
<RectangleSkeleton
|
||||
className="role-selector"
|
||||
width="64px"
|
||||
height="20px"
|
||||
borderRadius="3px"
|
||||
/>
|
||||
</StyledMemberLoader>
|
||||
))}
|
||||
<MemberLoader count={4} />
|
||||
</StyledMembersLoader>
|
||||
);
|
||||
};
|
||||
|
@ -369,7 +369,7 @@ class AuthStore {
|
||||
|
||||
login = async (user: TUser, hash: string, session = true) => {
|
||||
try {
|
||||
const response = (await api.user.login(user, hash, session)) as {
|
||||
const response = (await api.user.login(user, hash, "", session)) as {
|
||||
token: string;
|
||||
tfa: string;
|
||||
error: { message: unknown };
|
||||
|
@ -2114,6 +2114,7 @@ export const getBaseTheme = () => {
|
||||
folderLabelColor: "#A3A9AE",
|
||||
renamedItemColor: "#A3A9AE",
|
||||
oldRoleColor: "#657077",
|
||||
messageColor: "#333333",
|
||||
},
|
||||
|
||||
details: {
|
||||
@ -2720,6 +2721,7 @@ export const getBaseTheme = () => {
|
||||
upload: {
|
||||
color: gray,
|
||||
tooltipColor: lightCumulus,
|
||||
iconColor: lightErrorStatus,
|
||||
|
||||
shareButton: {
|
||||
color: gray,
|
||||
|
@ -2086,6 +2086,7 @@ const Dark: TTheme = {
|
||||
folderLabelColor: "#A3A9AE",
|
||||
renamedItemColor: "#A3A9AE",
|
||||
oldRoleColor: "#A3A9AE",
|
||||
messageColor: "#FFFFFF",
|
||||
},
|
||||
|
||||
details: {
|
||||
@ -2698,6 +2699,7 @@ const Dark: TTheme = {
|
||||
upload: {
|
||||
color: black,
|
||||
tooltipColor: "#F5E9BA",
|
||||
iconColor: darkErrorStatus,
|
||||
|
||||
shareButton: {
|
||||
color: gray,
|
||||
|
@ -25,6 +25,7 @@
|
||||
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||||
|
||||
export const INFO_PANEL_WIDTH = 400;
|
||||
export const TABLE_HEADER_HEIGHT = 40;
|
||||
|
||||
export function checkIsSSR() {
|
||||
return typeof window === "undefined";
|
||||
|
Loading…
Reference in New Issue
Block a user