transferring changes from Google to NextCloud
This commit is contained in:
parent
851a305d85
commit
b92a25719d
@ -8,7 +8,7 @@
|
||||
"AccessRightsUsersFromList": "{{users}} from the list",
|
||||
"AccountsWithoutEmails": "We found <1>{{users}} users</1> without emails. You can add necessary data to their accounts on the next step.",
|
||||
"AddEmails": "Add emails to incomplete accounts",
|
||||
"AddEmailsWarning": "You don<EFBFBD>t have users with emails. Please proceed to the next step to add them.",
|
||||
"AddEmailsWarning": "You don't have users with emails. Please proceed to the next step to add them.",
|
||||
"AddAllowedIP": "Add allowed IP address",
|
||||
"AdditionalResources": "Additional resources",
|
||||
"AdditionalResourcesDescription": "Choose whether you want to display links to additional resources in DocSpace menu.",
|
||||
|
@ -6,6 +6,7 @@ import ModalDialogContainer from "../ModalDialogContainer";
|
||||
|
||||
const CancelUploadDialog = ({
|
||||
isFifthStep,
|
||||
isSixthStep,
|
||||
visible,
|
||||
onClose,
|
||||
loading,
|
||||
@ -14,12 +15,13 @@ const CancelUploadDialog = ({
|
||||
const { t } = useTranslation(["Settings", "Common"]);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const modalBodyText = isFifthStep
|
||||
? t("Settings:WantToCancelDataImport")
|
||||
: t("Settings:WantToCancelUpload");
|
||||
const modalBodyText =
|
||||
isFifthStep || isSixthStep
|
||||
? t("Settings:WantToCancelDataImport")
|
||||
: t("Settings:WantToCancelUpload");
|
||||
|
||||
const onCancelProcess = () => {
|
||||
if (isFifthStep) {
|
||||
if (isFifthStep || isSixthStep) {
|
||||
navigate(-1);
|
||||
cancelMigration();
|
||||
} else {
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import ImportSection from "../../../sub-components/ImportSection";
|
||||
|
||||
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
|
||||
import PeopleIcon from "PUBLIC_DIR/images/catalog.accounts.react.svg";
|
||||
import UserIcon from "PUBLIC_DIR/images/catalog.user.react.svg";
|
||||
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
|
||||
|
||||
const SectionsWrapper = styled.div`
|
||||
display: flex;
|
||||
@ -17,27 +17,28 @@ const SectionsWrapper = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const FifthStep = ({ t, incrementStep, decrementStep }) => {
|
||||
const [isChecked, setIsChecked] = useState({
|
||||
users: true,
|
||||
pFiles: true,
|
||||
sFiles: true,
|
||||
});
|
||||
const FifthStep = ({
|
||||
t,
|
||||
incrementStep,
|
||||
decrementStep,
|
||||
toggles,
|
||||
setToggles,
|
||||
}) => {
|
||||
const [isChecked, setIsChecked] = useState(true);
|
||||
|
||||
const onChange = (name) => {
|
||||
setIsChecked((prevIsChecked) => ({
|
||||
...prevIsChecked,
|
||||
[name]: !prevIsChecked[name],
|
||||
}));
|
||||
const onChange = (e, name) => {
|
||||
const checked = e.target.checked;
|
||||
setToggles({ [name]: checked });
|
||||
};
|
||||
|
||||
const users = t("Settings:Employees")[0].toUpperCase() + t("Settings:Employees").slice(1);
|
||||
const users =
|
||||
t("Settings:Employees")[0].toUpperCase() + t("Settings:Employees").slice(1);
|
||||
|
||||
return (
|
||||
<SectionsWrapper>
|
||||
<ImportSection
|
||||
isChecked={isChecked.users}
|
||||
onChange={() => onChange("users")}
|
||||
isChecked={isChecked}
|
||||
onChange={() => setIsChecked((prev) => !prev)}
|
||||
sectionName={users}
|
||||
description={t("Settings:UsersSectionDescription")}
|
||||
exportSection={{ sectionName: users, workspace: "NextCloud" }}
|
||||
@ -49,10 +50,12 @@ const FifthStep = ({ t, incrementStep, decrementStep }) => {
|
||||
isDisabled
|
||||
/>
|
||||
<ImportSection
|
||||
isChecked={isChecked.pFiles}
|
||||
onChange={() => onChange("pFiles")}
|
||||
isChecked={toggles.importPersonalFiles}
|
||||
onChange={(e) => onChange(e, "importPersonalFiles")}
|
||||
sectionName={t("Settings:PersonalFiles")}
|
||||
description={t("Settings:PersonalFilesDescription", { serviceName: "Nextcloud" })}
|
||||
description={t("Settings:PersonalFilesDescription", {
|
||||
serviceName: "Nextcloud",
|
||||
})}
|
||||
exportSection={{
|
||||
sectionName: t("Settings:UsersFiles"),
|
||||
workspace: "NextCloud",
|
||||
@ -64,10 +67,12 @@ const FifthStep = ({ t, incrementStep, decrementStep }) => {
|
||||
}}
|
||||
/>
|
||||
<ImportSection
|
||||
isChecked={isChecked.sFiles}
|
||||
onChange={() => onChange("sFiles")}
|
||||
isChecked={toggles.importSharedFiles}
|
||||
onChange={(e) => onChange(e, "importSharedFiles")}
|
||||
sectionName={t("Settings:SharedFiles")}
|
||||
description={t("Settings:SharedFilesDescription", { serviceName: "Nextcloud" })}
|
||||
description={t("Settings:SharedFilesDescription", {
|
||||
serviceName: "Nextcloud",
|
||||
})}
|
||||
exportSection={{
|
||||
sectionName: t("Settings:SharedFiles"),
|
||||
workspace: "NextCloud",
|
||||
@ -91,4 +96,12 @@ const FifthStep = ({ t, incrementStep, decrementStep }) => {
|
||||
</SectionsWrapper>
|
||||
);
|
||||
};
|
||||
export default FifthStep;
|
||||
|
||||
export default inject(({ importAccountsStore }) => {
|
||||
const { toggles, setToggles } = importAccountsStore;
|
||||
|
||||
return {
|
||||
toggles,
|
||||
setToggles,
|
||||
};
|
||||
})(observer(FifthStep));
|
||||
|
@ -1,16 +1,14 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { CancelUploadDialog } from "SRC_DIR/components/dialogs";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import Text from "@docspace/components/text";
|
||||
import FileInput from "@docspace/components/file-input";
|
||||
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
|
||||
import ProgressBar from "@docspace/components/progress-bar";
|
||||
import Button from "@docspace/components/button";
|
||||
import { CancelUploadDialog } from "SRC_DIR/components/dialogs";
|
||||
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import FileInput from "@docspace/components/file-input";
|
||||
import ProgressBar from "@docspace/components/progress-bar";
|
||||
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
|
||||
|
||||
const Wrapper = styled.div`
|
||||
max-width: 350px;
|
||||
@ -43,19 +41,21 @@ const FirstStep = ({
|
||||
t,
|
||||
incrementStep,
|
||||
decrementStep,
|
||||
cancelUploadDialogVisible,
|
||||
setCancelUploadDialogVisible,
|
||||
cancelDialogVisble,
|
||||
setCancelDialogVisbile,
|
||||
initMigrationName,
|
||||
singleFileUploading,
|
||||
getMigrationStatus,
|
||||
setUsers,
|
||||
setData,
|
||||
isFileLoading,
|
||||
setIsFileLoading,
|
||||
cancelMigration,
|
||||
}) => {
|
||||
const [isSaveDisabled, setIsSaveDisabled] = useState(false);
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [searchParams] = useSearchParams();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onUploadFile = async (file) => {
|
||||
await singleFileUploading(file, setProgress);
|
||||
@ -64,12 +64,12 @@ const FirstStep = ({
|
||||
const res = await getMigrationStatus();
|
||||
|
||||
if (!res || res.parseResult.failedArchives.length > 0) {
|
||||
console.error("something went wrong");
|
||||
setIsFileLoading(false);
|
||||
clearInterval(interval);
|
||||
} else if (res.isCompleted) {
|
||||
setIsFileLoading(false);
|
||||
clearInterval(interval);
|
||||
setData(res);
|
||||
setUsers(res);
|
||||
setIsSaveDisabled(true);
|
||||
}
|
||||
@ -87,31 +87,44 @@ const FirstStep = ({
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
setCancelUploadDialogVisible(true);
|
||||
setCancelDialogVisbile(true);
|
||||
setProgress(0);
|
||||
setIsFileLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Text className="choose-backup-file">{t("Settings:ChooseBackupFile")}</Text>
|
||||
<Text className="choose-backup-file">
|
||||
{t("Settings:ChooseBackupFile")}
|
||||
</Text>
|
||||
<FileInput
|
||||
scale
|
||||
onInput={onSelectFile}
|
||||
className="upload-backup-input"
|
||||
placeholder={t("Settings:BackupFile")}
|
||||
scale
|
||||
isDisabled={isFileLoading}
|
||||
accept=".zip"
|
||||
/>
|
||||
{isFileLoading ? (
|
||||
<>
|
||||
<Text className="select-file-progress-text">{t("Settings:BackupFileUploading")}</Text>
|
||||
<ProgressBar percent={progress} className="select-file-progress-bar" />
|
||||
<Button size="small" label={t("Common:CancelButton")} onClick={onCancel} />
|
||||
<Text className="select-file-progress-text">
|
||||
{t("Settings:BackupFileUploading")}
|
||||
</Text>
|
||||
<ProgressBar
|
||||
percent={progress}
|
||||
className="select-file-progress-bar"
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onCancel}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<SaveCancelButtons
|
||||
className="upload-back-buttons"
|
||||
onSaveClick={incrementStep}
|
||||
onCancelClick={decrementStep}
|
||||
onCancelClick={() => navigate(-1)}
|
||||
saveButtonLabel={t("Settings:UploadToServer")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
displaySettings
|
||||
@ -120,11 +133,12 @@ const FirstStep = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
{cancelUploadDialogVisible && (
|
||||
{cancelDialogVisble && (
|
||||
<CancelUploadDialog
|
||||
visible={cancelUploadDialogVisible}
|
||||
visible={cancelDialogVisble}
|
||||
loading={isFileLoading}
|
||||
onClose={() => setCancelUploadDialogVisible(false)}
|
||||
onClose={() => setCancelDialogVisbile(false)}
|
||||
cancelMigration={cancelMigration}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
@ -137,19 +151,24 @@ export default inject(({ dialogsStore, importAccountsStore }) => {
|
||||
singleFileUploading,
|
||||
getMigrationStatus,
|
||||
setUsers,
|
||||
setData,
|
||||
isFileLoading,
|
||||
setIsFileLoading,
|
||||
cancelMigration,
|
||||
} = importAccountsStore;
|
||||
const { cancelUploadDialogVisible, setCancelUploadDialogVisible } = dialogsStore;
|
||||
const { cancelUploadDialogVisible, setCancelUploadDialogVisible } =
|
||||
dialogsStore;
|
||||
|
||||
return {
|
||||
setUsers,
|
||||
initMigrationName,
|
||||
singleFileUploading,
|
||||
getMigrationStatus,
|
||||
initMigrationName,
|
||||
cancelUploadDialogVisible,
|
||||
setCancelUploadDialogVisible,
|
||||
setUsers,
|
||||
setData,
|
||||
isFileLoading,
|
||||
setIsFileLoading,
|
||||
cancelMigration,
|
||||
cancelDialogVisble: cancelUploadDialogVisible,
|
||||
setCancelDialogVisbile: setCancelUploadDialogVisible,
|
||||
};
|
||||
})(observer(FirstStep));
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useRef } from "react";
|
||||
import { useRef } from "react";
|
||||
import Row from "@docspace/components/row";
|
||||
import UsersRowContent from "./UsersRowContent";
|
||||
|
||||
const UserskRow = (props) => {
|
||||
const { t, data, sectionWidth, isChecked, toggleAccount } = props;
|
||||
const { data, sectionWidth, typeOptions, isChecked, toggleAccount } = props;
|
||||
|
||||
const roleSelectorRef = useRef();
|
||||
|
||||
@ -18,15 +18,20 @@ const UserskRow = (props) => {
|
||||
return (
|
||||
<Row
|
||||
sectionWidth={sectionWidth}
|
||||
key={data.key}
|
||||
data={data}
|
||||
checked={isChecked}
|
||||
checkbox
|
||||
onClick={handleAccountToggle}>
|
||||
checkbox={isChecked}
|
||||
onClick={handleAccountToggle}
|
||||
contextButtonSpacerWidth="0"
|
||||
>
|
||||
<UsersRowContent
|
||||
t={t}
|
||||
id={data.key}
|
||||
sectionWidth={sectionWidth}
|
||||
displayName={data.displayName}
|
||||
email={data.email}
|
||||
type={data.userType}
|
||||
typeOptions={typeOptions}
|
||||
roleSelectorRef={roleSelectorRef}
|
||||
/>
|
||||
</Row>
|
||||
|
@ -1,9 +1,10 @@
|
||||
import React, { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled from "styled-components";
|
||||
import Text from "@docspace/components/text";
|
||||
import RowContent from "@docspace/components/row-content";
|
||||
|
||||
import AccessRightSelect from "@docspace/components/access-right-select";
|
||||
import Text from "@docspace/components/text";
|
||||
import Box from "@docspace/components/box";
|
||||
import RowContent from "@docspace/components/row-content";
|
||||
import ComboBox from "@docspace/components/combobox";
|
||||
|
||||
const StyledRowContent = styled(RowContent)`
|
||||
display: flex;
|
||||
@ -54,22 +55,22 @@ const StyledRowContent = styled(RowContent)`
|
||||
}
|
||||
`;
|
||||
|
||||
const UsersRowContent = ({ t, sectionWidth, displayName, email, roleSelectorRef }) => {
|
||||
const data = [
|
||||
{
|
||||
key: "role-DocSpace-admin",
|
||||
label: t("Settings:DocSpaceAdmin"),
|
||||
},
|
||||
{
|
||||
key: "role-Room-admin",
|
||||
label: t("Settings:RoomAdmin"),
|
||||
},
|
||||
{
|
||||
key: "role-Power-user",
|
||||
label: t("Settings:PowerUser"),
|
||||
},
|
||||
];
|
||||
const [selectedType, setSelectedType] = useState(data[2]);
|
||||
const UsersRowContent = ({
|
||||
id,
|
||||
sectionWidth,
|
||||
displayName,
|
||||
email,
|
||||
typeOptions,
|
||||
roleSelectorRef,
|
||||
type,
|
||||
changeType,
|
||||
}) => {
|
||||
const onSelectUser = (e) => {
|
||||
changeType(id, e.key);
|
||||
};
|
||||
|
||||
const selectedOption =
|
||||
typeOptions.find((option) => option.key === type) || {};
|
||||
|
||||
return (
|
||||
<StyledRowContent sectionWidth={sectionWidth}>
|
||||
@ -82,18 +83,26 @@ const UsersRowContent = ({ t, sectionWidth, displayName, email, roleSelectorRef
|
||||
</Text>
|
||||
</div>
|
||||
<div ref={roleSelectorRef}>
|
||||
<AccessRightSelect
|
||||
accessOptions={data}
|
||||
selectedOption={selectedType}
|
||||
scaledOptions={false}
|
||||
scaled={false}
|
||||
<ComboBox
|
||||
className="user-type"
|
||||
selectedOption={selectedOption}
|
||||
options={typeOptions}
|
||||
onSelect={onSelectUser}
|
||||
scaled
|
||||
size="content"
|
||||
displaySelectedOption
|
||||
modernView
|
||||
manualWidth="fit-content"
|
||||
className="role-type-selector"
|
||||
onSelect={setSelectedType}
|
||||
/>
|
||||
</div>
|
||||
</StyledRowContent>
|
||||
);
|
||||
};
|
||||
|
||||
export default UsersRowContent;
|
||||
export default inject(({ importAccountsStore }) => {
|
||||
const { changeType } = importAccountsStore;
|
||||
|
||||
return {
|
||||
changeType,
|
||||
};
|
||||
})(observer(UsersRowContent));
|
||||
|
@ -4,21 +4,77 @@ import { isMobile } from "react-device-detect";
|
||||
import { tablet } from "@docspace/components/utils/device";
|
||||
import styled from "styled-components";
|
||||
|
||||
import RowContainer from "@docspace/components/row-container";
|
||||
import UsersRow from "./UsersRow";
|
||||
|
||||
import EmptyScreenContainer from "@docspace/components/empty-screen-container";
|
||||
import IconButton from "@docspace/components/icon-button";
|
||||
import Link from "@docspace/components/link";
|
||||
import Box from "@docspace/components/box";
|
||||
import TableGroupMenu from "@docspace/components/table-container/TableGroupMenu";
|
||||
import RowContainer from "@docspace/components/row-container";
|
||||
import Row from "@docspace/components/row";
|
||||
import Text from "@docspace/components/text";
|
||||
import ChangeTypeReactSvgUrl from "PUBLIC_DIR/images/change.type.react.svg?url";
|
||||
import EmptyScreenUserReactSvgUrl from "PUBLIC_DIR/images/empty_screen_user.react.svg?url";
|
||||
import ClearEmptyFilterSvgUrl from "PUBLIC_DIR/images/clear.empty.filter.svg?url";
|
||||
|
||||
import { mockData } from "../../mockData";
|
||||
// import { mockData } from "../../mockData";
|
||||
|
||||
const StyledRowContainer = styled(RowContainer)`
|
||||
margin: 20px 0;
|
||||
margin: 0 0 20px;
|
||||
|
||||
.table-group-menu {
|
||||
height: 60px;
|
||||
position: relative;
|
||||
z-index: 201;
|
||||
left: -20px;
|
||||
top: 25px;
|
||||
width: 100%;
|
||||
|
||||
.table-container_group-menu {
|
||||
padding: 0px 20px;
|
||||
border-image-slice: 0;
|
||||
box-shadow: rgba(4, 15, 27, 0.07) 0px 15px 20px;
|
||||
}
|
||||
|
||||
.table-container_group-menu-checkbox {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.table-container_group-menu-separator {
|
||||
margin: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-container-text {
|
||||
font-size: 12px;
|
||||
color: ${(props) =>
|
||||
props.theme.client.settings.migration.tableRowTextColor};
|
||||
}
|
||||
|
||||
.table-container_header {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.ec-desc {
|
||||
max-width: 348px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledRow = styled(Row)`
|
||||
box-sizing: border-box;
|
||||
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;
|
||||
@ -29,18 +85,30 @@ const StyledRow = styled(Row)`
|
||||
const RowView = (props) => {
|
||||
const {
|
||||
t,
|
||||
users,
|
||||
sectionWidth,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
sectionWidth,
|
||||
accountsData,
|
||||
typeOptions,
|
||||
checkedAccounts,
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
onCheckAccounts,
|
||||
setSearchValue,
|
||||
} = props;
|
||||
const rowRef = useRef(null);
|
||||
|
||||
const toggleAll = (e) => toggleAllAccounts({ target: { checked: !e.target.checked } }, mockData);
|
||||
const toggleAll = (checked) => {
|
||||
onCheckAccounts(checked, users);
|
||||
};
|
||||
|
||||
const onClearFilter = () => {
|
||||
setSearchValue("");
|
||||
};
|
||||
|
||||
const isIndeterminate =
|
||||
checkedAccounts.length > 0 && checkedAccounts.length !== users.length;
|
||||
|
||||
useEffect(() => {
|
||||
if (viewAs !== "table" && viewAs !== "row") return;
|
||||
@ -50,32 +118,79 @@ const RowView = (props) => {
|
||||
} else {
|
||||
viewAs !== "table" && setViewAs("table");
|
||||
}
|
||||
|
||||
return cleanCheckedAccounts;
|
||||
}, [sectionWidth]);
|
||||
|
||||
const headerMenu = [
|
||||
{
|
||||
id: "change-type",
|
||||
key: "change-type",
|
||||
label: t("ChangeUserTypeDialog:ChangeUserTypeButton"),
|
||||
disabled: false,
|
||||
withDropDown: true,
|
||||
options: typeOptions,
|
||||
iconUrl: ChangeTypeReactSvgUrl,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<StyledRowContainer useReactWindow={false}>
|
||||
<StyledRow
|
||||
sectionWidth={sectionWidth}
|
||||
checkbox
|
||||
checked={checkedAccounts.length === mockData.length}
|
||||
onClick={toggleAll}
|
||||
indeterminate={checkedAccounts.length > 0 && checkedAccounts.length !== mockData.length}>
|
||||
<Text color="#a3a9ae" fontWeight={600} fontSize="12px">
|
||||
{t("Common:Name")}
|
||||
</Text>
|
||||
</StyledRow>
|
||||
{accountsData.map((data) => (
|
||||
<UsersRow
|
||||
t={t}
|
||||
key={data.id}
|
||||
data={data}
|
||||
sectionWidth={sectionWidth}
|
||||
toggleAccount={() => toggleAccount(data.id)}
|
||||
isChecked={isAccountChecked(data.id)}
|
||||
<StyledRowContainer forwardedRef={rowRef} useReactWindow={false}>
|
||||
{checkedAccounts.length > 0 && (
|
||||
<div className="table-group-menu">
|
||||
<TableGroupMenu
|
||||
sectionWidth={sectionWidth}
|
||||
headerMenu={headerMenu}
|
||||
withoutInfoPanelToggler
|
||||
withComboBox={false}
|
||||
isIndeterminate={isIndeterminate}
|
||||
isChecked={checkedAccounts.length === users.length}
|
||||
onChange={toggleAll}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{accountsData.length > 0 ? (
|
||||
<>
|
||||
<StyledRow key="Name" sectionWidth={sectionWidth} onClick={toggleAll}>
|
||||
<Text className="row-header-title">{t("Common:Name")}</Text>
|
||||
</StyledRow>
|
||||
|
||||
{users.map((data) => (
|
||||
<UsersRow
|
||||
key={data.key}
|
||||
data={data}
|
||||
sectionWidth={sectionWidth}
|
||||
typeOptions={typeOptions}
|
||||
isChecked={isAccountChecked(data.key)}
|
||||
toggleAccount={() => toggleAccount(data.key)}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreenContainer
|
||||
imageSrc={EmptyScreenUserReactSvgUrl}
|
||||
imageAlt="Empty Screen user image"
|
||||
headerText={t("People:NotFoundUsers")}
|
||||
descriptionText={t("People:NotFoundUsersDesc")}
|
||||
buttons={
|
||||
<Box displayProp="flex" alignItems="center">
|
||||
<IconButton
|
||||
className="clear-icon"
|
||||
isFill
|
||||
size="12"
|
||||
onClick={onClearFilter}
|
||||
iconName={ClearEmptyFilterSvgUrl}
|
||||
/>
|
||||
<Link
|
||||
type="action"
|
||||
isHovered={true}
|
||||
fontWeight="600"
|
||||
onClick={onClearFilter}
|
||||
>
|
||||
{t("Common:ClearFilter")}
|
||||
</Link>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
)}
|
||||
</StyledRowContainer>
|
||||
);
|
||||
};
|
||||
@ -83,20 +198,24 @@ const RowView = (props) => {
|
||||
export default inject(({ setup, importAccountsStore }) => {
|
||||
const { viewAs, setViewAs } = setup;
|
||||
const {
|
||||
users,
|
||||
checkedAccounts,
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
onCheckAccounts,
|
||||
setSearchValue,
|
||||
} = importAccountsStore;
|
||||
|
||||
return {
|
||||
users,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
checkedAccounts,
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
onCheckAccounts,
|
||||
setSearchValue,
|
||||
};
|
||||
})(observer(RowView));
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import TableHeader from "@docspace/components/table-container/TableHeader";
|
||||
@ -81,8 +81,8 @@ const UsersTableHeader = (props) => {
|
||||
|
||||
setColumns((prevColumns) =>
|
||||
prevColumns.map((item, index) =>
|
||||
index === columnIndex ? { ...item, enable: !item.enable } : item,
|
||||
),
|
||||
index === columnIndex ? { ...item, enable: !item.enable } : item
|
||||
)
|
||||
);
|
||||
|
||||
const tableColumns = columns.map((c) => c.enable && c.key);
|
||||
|
@ -1,12 +1,12 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
import { useRef } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import TableRow from "@docspace/components/table-container/TableRow";
|
||||
import TableCell from "@docspace/components/table-container/TableCell";
|
||||
|
||||
import AccessRightSelect from "@docspace/components/access-right-select";
|
||||
import Text from "@docspace/components/text";
|
||||
import Checkbox from "@docspace/components/checkbox";
|
||||
import ComboBox from "@docspace/components/combobox";
|
||||
|
||||
const StyledTableRow = styled(TableRow)`
|
||||
.table-container_cell {
|
||||
@ -57,24 +57,24 @@ const StyledTableRow = styled(TableRow)`
|
||||
}
|
||||
`;
|
||||
|
||||
const UsersTableRow = ({ t, displayName, email, isChecked, toggleAccount }) => {
|
||||
const data = [
|
||||
{
|
||||
key: "DocSpaceAdmin",
|
||||
label: t("Common:DocSpaceAdmin"),
|
||||
},
|
||||
{
|
||||
key: "RoomAdmin",
|
||||
label: t("Common:RoomAdmin"),
|
||||
},
|
||||
{
|
||||
key: "PowerUser",
|
||||
label: t("Common:PowerUser"),
|
||||
},
|
||||
];
|
||||
|
||||
const UsersTableRow = ({
|
||||
id,
|
||||
displayName,
|
||||
email,
|
||||
typeOptions,
|
||||
isChecked,
|
||||
toggleAccount,
|
||||
type,
|
||||
changeType,
|
||||
}) => {
|
||||
const roleSelectorRef = useRef();
|
||||
const [selectedType, setSelectedType] = useState(data[2]);
|
||||
|
||||
const onSelectUser = (e) => {
|
||||
changeType(id, e.key);
|
||||
};
|
||||
|
||||
const selectedOption =
|
||||
typeOptions.find((option) => option.key === type) || {};
|
||||
|
||||
const handleAccountToggle = (e) => {
|
||||
e.preventDefault();
|
||||
@ -87,7 +87,7 @@ const UsersTableRow = ({ t, displayName, email, isChecked, toggleAccount }) => {
|
||||
return (
|
||||
<StyledTableRow checked={isChecked} onClick={handleAccountToggle}>
|
||||
<TableCell>
|
||||
<Checkbox onChange={handleAccountToggle} isChecked={isChecked} />
|
||||
<Checkbox isChecked={isChecked} onChange={handleAccountToggle} />
|
||||
<Text fontWeight={600} className="textOverflow">
|
||||
{displayName}
|
||||
</Text>
|
||||
@ -95,19 +95,26 @@ const UsersTableRow = ({ t, displayName, email, isChecked, toggleAccount }) => {
|
||||
|
||||
<TableCell>
|
||||
<div ref={roleSelectorRef}>
|
||||
<AccessRightSelect
|
||||
accessOptions={data}
|
||||
selectedOption={selectedType}
|
||||
scaledOptions={false}
|
||||
scaled={false}
|
||||
<ComboBox
|
||||
className="user-type"
|
||||
selectedOption={selectedOption}
|
||||
options={typeOptions}
|
||||
onSelect={onSelectUser}
|
||||
scaled
|
||||
size="content"
|
||||
displaySelectedOption
|
||||
modernView
|
||||
manualWidth="fit-content"
|
||||
className="role-type-selector"
|
||||
onSelect={setSelectedType}
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Text lineHeight="20px" fontWeight={600} color="#A3A9AE" className="textOverflow">
|
||||
<Text
|
||||
lineHeight="20px"
|
||||
fontWeight={600}
|
||||
color="#A3A9AE"
|
||||
className="textOverflow"
|
||||
>
|
||||
{email}
|
||||
</Text>
|
||||
</TableCell>
|
||||
@ -115,4 +122,10 @@ const UsersTableRow = ({ t, displayName, email, isChecked, toggleAccount }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default UsersTableRow;
|
||||
export default inject(({ importAccountsStore }) => {
|
||||
const { changeType } = importAccountsStore;
|
||||
|
||||
return {
|
||||
changeType,
|
||||
};
|
||||
})(observer(UsersTableRow));
|
||||
|
@ -3,23 +3,53 @@ import { inject, observer } from "mobx-react";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
import styled from "styled-components";
|
||||
|
||||
import UsersTableHeader from "./UsersTableHeader";
|
||||
import UsersTableRow from "./UsersTableRow";
|
||||
|
||||
import EmptyScreenContainer from "@docspace/components/empty-screen-container";
|
||||
import IconButton from "@docspace/components/icon-button";
|
||||
import Link from "@docspace/components/link";
|
||||
import Box from "@docspace/components/box";
|
||||
import TableGroupMenu from "@docspace/components/table-container/TableGroupMenu";
|
||||
import TableContainer from "@docspace/components/table-container/TableContainer";
|
||||
import TableBody from "@docspace/components/table-container/TableBody";
|
||||
import ChangeTypeReactSvgUrl from "PUBLIC_DIR/images/change.type.react.svg?url";
|
||||
import EmptyScreenUserReactSvgUrl from "PUBLIC_DIR/images/empty_screen_user.react.svg?url";
|
||||
import ClearEmptyFilterSvgUrl from "PUBLIC_DIR/images/clear.empty.filter.svg?url";
|
||||
|
||||
import { mockData } from "../../mockData";
|
||||
|
||||
const TABLE_VERSION = "6";
|
||||
const COLUMNS_SIZE = `nextcloudFourthColumnsSize_ver-${TABLE_VERSION}`;
|
||||
const INFO_PANEL_COLUMNS_SIZE = `infoPanelNextcloudFourthColumnsSize_ver-${TABLE_VERSION}`;
|
||||
// import { mockData } from "../../mockData";
|
||||
|
||||
const StyledTableContainer = styled(TableContainer)`
|
||||
margin: 0.5px 0px 20px;
|
||||
margin: 0 0 20px;
|
||||
|
||||
.table-group-menu {
|
||||
height: 69px;
|
||||
position: relative;
|
||||
z-index: 201;
|
||||
left: -20px;
|
||||
top: 28px;
|
||||
width: 100%;
|
||||
|
||||
.table-container_group-menu {
|
||||
border-image-slice: 0;
|
||||
border-image-source: none;
|
||||
border-bottom: ${(props) =>
|
||||
props.theme.client.settings.migration.workspaceBorder};
|
||||
box-shadow: rgba(4, 15, 27, 0.07) 0px 15px 20px;
|
||||
}
|
||||
|
||||
.table-container_group-menu-checkbox {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.table-container_group-menu-separator {
|
||||
margin: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-container-text {
|
||||
font-size: 12px;
|
||||
color: ${(props) => props.theme.client.settings.migration.tableHeaderText};
|
||||
}
|
||||
|
||||
.table-container_header {
|
||||
@ -30,36 +60,64 @@ const StyledTableContainer = styled(TableContainer)`
|
||||
margin-top: -1px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: ${(props) => (props.theme.isBase ? "#F8F9F9" : "#282828")};
|
||||
background: ${(props) =>
|
||||
props.theme.client.settings.migration.tableRowHoverColor};
|
||||
}
|
||||
}
|
||||
|
||||
.clear-icon {
|
||||
margin-right: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.ec-desc {
|
||||
max-width: 618px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledTableContainer.defaultProps = { theme: Base };
|
||||
|
||||
const TABLE_VERSION = "6";
|
||||
const COLUMNS_SIZE = `nextcloudFourthColumnsSize_ver-${TABLE_VERSION}`;
|
||||
const INFO_PANEL_COLUMNS_SIZE = `infoPanelNextcloudFourthColumnsSize_ver-${TABLE_VERSION}`;
|
||||
|
||||
const TableView = (props) => {
|
||||
const {
|
||||
t,
|
||||
users,
|
||||
userId,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
sectionWidth,
|
||||
accountsData,
|
||||
typeOptions,
|
||||
checkedAccounts,
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
onCheckAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
setSearchValue,
|
||||
} = props;
|
||||
const [hideColumns, setHideColumns] = useState(false);
|
||||
const tableRef = useRef(null);
|
||||
const [hideColumns, setHideColumns] = useState(false);
|
||||
const columnStorageName = `${COLUMNS_SIZE}=${userId}`;
|
||||
const columnInfoPanelStorageName = `${INFO_PANEL_COLUMNS_SIZE}=${userId}`;
|
||||
|
||||
const isIndeterminate =
|
||||
checkedAccounts.length > 0 && checkedAccounts.length !== users.length;
|
||||
|
||||
const toggleAll = (checked) => {
|
||||
onCheckAccounts(checked, users);
|
||||
};
|
||||
|
||||
const toggleAll = (e) => toggleAllAccounts(e, mockData);
|
||||
const handleToggle = (e, id) => {
|
||||
e.stopPropagation();
|
||||
toggleAccount(id);
|
||||
};
|
||||
|
||||
const onClearFilter = () => {
|
||||
setSearchValue("");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!sectionWidth) return;
|
||||
if (sectionWidth < 1025 || isMobile) {
|
||||
@ -67,48 +125,101 @@ const TableView = (props) => {
|
||||
} else {
|
||||
viewAs !== "table" && setViewAs("table");
|
||||
}
|
||||
|
||||
return cleanCheckedAccounts;
|
||||
}, [sectionWidth]);
|
||||
|
||||
const columnStorageName = `${COLUMNS_SIZE}=${userId}`;
|
||||
const columnInfoPanelStorageName = `${INFO_PANEL_COLUMNS_SIZE}=${userId}`;
|
||||
const headerMenu = [
|
||||
{
|
||||
id: "change-type",
|
||||
key: "change-type",
|
||||
label: t("ChangeUserTypeDialog:ChangeUserTypeButton"),
|
||||
disabled: false,
|
||||
withDropDown: true,
|
||||
options: typeOptions,
|
||||
iconUrl: ChangeTypeReactSvgUrl,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<StyledTableContainer forwardedRef={tableRef} useReactWindow>
|
||||
<UsersTableHeader
|
||||
t={t}
|
||||
sectionWidth={sectionWidth}
|
||||
tableRef={tableRef}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
setHideColumns={setHideColumns}
|
||||
isIndeterminate={checkedAccounts.length > 0 && checkedAccounts.length !== mockData.length}
|
||||
isChecked={checkedAccounts.length === mockData.length}
|
||||
toggleAll={toggleAll}
|
||||
/>
|
||||
<TableBody
|
||||
itemHeight={49}
|
||||
useReactWindow
|
||||
infoPanelVisible={false}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
filesLength={accountsData.length}
|
||||
hasMoreFiles={false}
|
||||
itemCount={accountsData.length}
|
||||
fetchMoreFiles={() => {}}>
|
||||
{accountsData.map((data) => (
|
||||
<UsersTableRow
|
||||
t={t}
|
||||
key={data.id}
|
||||
displayName={data.displayName}
|
||||
email={data.email}
|
||||
hideColumns={hideColumns}
|
||||
isChecked={isAccountChecked(data.id)}
|
||||
toggleAccount={(e) => handleToggle(e, data.id)}
|
||||
{checkedAccounts.length > 0 && (
|
||||
<div className="table-group-menu">
|
||||
<TableGroupMenu
|
||||
sectionWidth={sectionWidth}
|
||||
headerMenu={headerMenu}
|
||||
withoutInfoPanelToggler
|
||||
withComboBox={false}
|
||||
isIndeterminate={isIndeterminate}
|
||||
isChecked={checkedAccounts.length === users.length}
|
||||
onChange={toggleAll}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
</div>
|
||||
)}
|
||||
{accountsData.length > 0 ? (
|
||||
<>
|
||||
<UsersTableHeader
|
||||
t={t}
|
||||
sectionWidth={sectionWidth}
|
||||
tableRef={tableRef}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
isIndeterminate={isIndeterminate}
|
||||
isChecked={checkedAccounts.length === users.length}
|
||||
toggleAll={toggleAll}
|
||||
setHideColumns={setHideColumns}
|
||||
/>
|
||||
<TableBody
|
||||
itemHeight={49}
|
||||
useReactWindow
|
||||
infoPanelVisible={false}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
filesLength={accountsData.length}
|
||||
hasMoreFiles={false}
|
||||
itemCount={accountsData.length}
|
||||
fetchMoreFiles={() => {}}
|
||||
>
|
||||
{users.map((data) => (
|
||||
<UsersTableRow
|
||||
key={data.key}
|
||||
id={data.key}
|
||||
type={data.userType}
|
||||
displayName={data.displayName}
|
||||
email={data.email}
|
||||
typeOptions={typeOptions}
|
||||
hideColumns={hideColumns}
|
||||
isChecked={isAccountChecked(data.key)}
|
||||
toggleAccount={(e) => handleToggle(e, data.key)}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreenContainer
|
||||
imageSrc={EmptyScreenUserReactSvgUrl}
|
||||
imageAlt="Empty Screen user image"
|
||||
headerText={t("People:NotFoundUsers")}
|
||||
descriptionText={t("People:NotFoundUsersDesc")}
|
||||
buttons={
|
||||
<Box displayProp="flex" alignItems="center">
|
||||
<IconButton
|
||||
className="clear-icon"
|
||||
isFill
|
||||
size="12"
|
||||
onClick={onClearFilter}
|
||||
iconName={ClearEmptyFilterSvgUrl}
|
||||
/>
|
||||
<Link
|
||||
type="action"
|
||||
isHovered={true}
|
||||
fontWeight="600"
|
||||
onClick={onClearFilter}
|
||||
>
|
||||
{t("Common:ClearFilter")}
|
||||
</Link>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</StyledTableContainer>
|
||||
);
|
||||
};
|
||||
@ -117,14 +228,17 @@ export default inject(({ setup, auth, importAccountsStore }) => {
|
||||
const { viewAs, setViewAs } = setup;
|
||||
const { id: userId } = auth.userStore.user;
|
||||
const {
|
||||
users,
|
||||
checkedAccounts,
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
onCheckAccounts,
|
||||
setSearchValue,
|
||||
} = importAccountsStore;
|
||||
|
||||
return {
|
||||
users,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
userId,
|
||||
@ -132,6 +246,7 @@ export default inject(({ setup, auth, importAccountsStore }) => {
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
onCheckAccounts,
|
||||
setSearchValue,
|
||||
};
|
||||
})(observer(TableView));
|
||||
|
@ -1,30 +1,65 @@
|
||||
import React from "react";
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { Consumer } from "@docspace/components/utils/context";
|
||||
|
||||
import TableView from "./TableView";
|
||||
import RowView from "./RowView";
|
||||
|
||||
const AccountsTable = (props) => {
|
||||
const { t, viewAs, accountsData } = props;
|
||||
const { t, viewAs, accountsData, changeTypeGroup } = props;
|
||||
|
||||
const onChangeType = (key) => {
|
||||
changeTypeGroup(key);
|
||||
};
|
||||
|
||||
const typeOptions = [
|
||||
{
|
||||
key: "DocSpaceAdmin",
|
||||
label: t("Common:DocSpaceAdmin"),
|
||||
onClick: () => onChangeType("DocSpaceAdmin"),
|
||||
},
|
||||
{
|
||||
key: "RoomAdmin",
|
||||
label: t("Common:RoomAdmin"),
|
||||
onClick: () => onChangeType("RoomAdmin"),
|
||||
},
|
||||
{
|
||||
key: "User",
|
||||
label: t("Common:PowerUser"),
|
||||
onClick: () => onChangeType("User"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Consumer>
|
||||
{(context) =>
|
||||
viewAs === "table" ? (
|
||||
<TableView t={t} sectionWidth={context.sectionWidth} accountsData={accountsData} />
|
||||
<TableView
|
||||
t={t}
|
||||
sectionWidth={context.sectionWidth}
|
||||
accountsData={accountsData}
|
||||
typeOptions={typeOptions}
|
||||
/>
|
||||
) : (
|
||||
<RowView t={t} sectionWidth={context.sectionWidth} accountsData={accountsData} />
|
||||
<RowView
|
||||
t={t}
|
||||
sectionWidth={context.sectionWidth}
|
||||
accountsData={accountsData}
|
||||
typeOptions={typeOptions}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</Consumer>
|
||||
);
|
||||
};
|
||||
export default inject(({ setup }) => {
|
||||
export default inject(({ setup, importAccountsStore }) => {
|
||||
const { viewAs } = setup;
|
||||
const { changeTypeGroup } = importAccountsStore;
|
||||
|
||||
return {
|
||||
viewAs,
|
||||
changeTypeGroup,
|
||||
};
|
||||
})(observer(AccountsTable));
|
||||
})(
|
||||
withTranslation(["ChangeUserTypeDialog", "People"])(observer(AccountsTable))
|
||||
);
|
||||
|
@ -1,25 +1,45 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
|
||||
import SearchInput from "@docspace/components/search-input";
|
||||
|
||||
import AccountsTable from "./AccountsTable";
|
||||
import AccountsPaging from "../../../sub-components/AccountsPaging";
|
||||
|
||||
import { Wrapper } from "../StyledStepper";
|
||||
|
||||
import { mockData } from "./mockData";
|
||||
// import { mockData } from "./mockData";
|
||||
|
||||
const FourthStep = (props) => {
|
||||
const { t, incrementStep, decrementStep } = props;
|
||||
const {
|
||||
t,
|
||||
incrementStep,
|
||||
decrementStep,
|
||||
checkedAccounts,
|
||||
users,
|
||||
searchValue,
|
||||
setSearchValue,
|
||||
} = props;
|
||||
|
||||
const [dataPortion, setDataPortion] = useState(mockData.slice(0, 25));
|
||||
const [dataPortion, setDataPortion] = useState(users.slice(0, 25));
|
||||
|
||||
const handleDataChange = (leftBoundary, rightBoundary) => {
|
||||
setDataPortion(mockData.slice(leftBoundary, rightBoundary));
|
||||
setDataPortion(users.slice(leftBoundary, rightBoundary));
|
||||
};
|
||||
|
||||
const onChangeInput = (value) => {
|
||||
setSearchValue(value);
|
||||
};
|
||||
|
||||
const onClearSearchInput = () => {
|
||||
setSearchValue("");
|
||||
};
|
||||
|
||||
const filteredAccounts = dataPortion.filter(
|
||||
(data) =>
|
||||
data.displayName.toLowerCase().startsWith(searchValue.toLowerCase()) ||
|
||||
data.email.toLowerCase().startsWith(searchValue.toLowerCase())
|
||||
);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<SaveCancelButtons
|
||||
@ -32,35 +52,50 @@ const FourthStep = (props) => {
|
||||
displaySettings={true}
|
||||
/>
|
||||
|
||||
<SearchInput
|
||||
id="search-users-input"
|
||||
onChange={() => console.log("changed")}
|
||||
onClearSearch={() => console.log("cleared")}
|
||||
placeholder={t("Common:Search")}
|
||||
/>
|
||||
<AccountsTable t={t} accountsData={dataPortion} />
|
||||
|
||||
{mockData.length > 25 && (
|
||||
<AccountsPaging t={t} numberOfItems={mockData.length} setDataPortion={handleDataChange} />
|
||||
{!checkedAccounts.length > 0 && (
|
||||
<SearchInput
|
||||
id="search-users-type-input"
|
||||
placeholder={t("Common:Search")}
|
||||
value={searchValue}
|
||||
onChange={onChangeInput}
|
||||
refreshTimeout={100}
|
||||
onClearSearch={onClearSearchInput}
|
||||
/>
|
||||
)}
|
||||
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
onSaveClick={incrementStep}
|
||||
onCancelClick={decrementStep}
|
||||
showReminder={true}
|
||||
saveButtonLabel={t("Settings:NextStep")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
displaySettings={true}
|
||||
/>
|
||||
<AccountsTable t={t} accountsData={filteredAccounts} />
|
||||
|
||||
{users.length > 25 && (
|
||||
<AccountsPaging
|
||||
t={t}
|
||||
numberOfItems={users.length}
|
||||
setDataPortion={handleDataChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
{filteredAccounts.length > 0 && (
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
onSaveClick={incrementStep}
|
||||
onCancelClick={decrementStep}
|
||||
showReminder={true}
|
||||
saveButtonLabel={t("Settings:NextStep")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
displaySettings={true}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ setup }) => {
|
||||
const { viewAs } = setup;
|
||||
export default inject(({ importAccountsStore }) => {
|
||||
const { checkedAccounts, users, searchValue, setSearchValue } =
|
||||
importAccountsStore;
|
||||
|
||||
return {
|
||||
viewAs,
|
||||
checkedAccounts,
|
||||
users,
|
||||
searchValue,
|
||||
setSearchValue,
|
||||
};
|
||||
})(observer(FourthStep));
|
||||
|
@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import Row from "@docspace/components/row";
|
||||
import UsersRowContent from "./UsersRowContent";
|
||||
|
||||
@ -9,10 +8,12 @@ const UsersRow = (props) => {
|
||||
<Row
|
||||
sectionWidth={sectionWidth}
|
||||
data={data}
|
||||
checked={isChecked}
|
||||
checkbox
|
||||
checked={isChecked}
|
||||
onClick={toggleAccount}
|
||||
onSelect={toggleAccount}>
|
||||
onSelect={toggleAccount}
|
||||
contextButtonSpacerWidth="0"
|
||||
>
|
||||
<UsersRowContent
|
||||
t={t}
|
||||
sectionWidth={sectionWidth}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import Text from "@docspace/components/text";
|
||||
import RowContent from "@docspace/components/row-content";
|
||||
@ -33,13 +32,21 @@ const StyledRowContent = styled(RowContent)`
|
||||
}
|
||||
`;
|
||||
|
||||
const UsersRowContent = ({ t, sectionWidth, displayName, email, isDuplicate }) => {
|
||||
const UsersRowContent = ({
|
||||
t,
|
||||
sectionWidth,
|
||||
displayName,
|
||||
email,
|
||||
isDuplicate,
|
||||
}) => {
|
||||
return (
|
||||
<StyledRowContent sectionWidth={sectionWidth}>
|
||||
<div className="import-accounts-name">
|
||||
{displayName}
|
||||
{isDuplicate && (
|
||||
<span className="import-account-duplicate"> ({t("Settings:ExistingAccount")})</span>
|
||||
<span className="import-account-duplicate">
|
||||
({t("Settings:ExistingAccount")})
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<Text fontSize="12px" color="#a3a9ae" className="user-email">
|
||||
|
@ -1,24 +1,52 @@
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { tablet } from "@docspace/components/utils/device";
|
||||
import styled from "styled-components";
|
||||
|
||||
import EmptyScreenContainer from "@docspace/components/empty-screen-container";
|
||||
import IconButton from "@docspace/components/icon-button";
|
||||
import Link from "@docspace/components/link";
|
||||
import Box from "@docspace/components/box";
|
||||
import RowContainer from "@docspace/components/row-container";
|
||||
import UsersRow from "./UsersRow";
|
||||
import Row from "@docspace/components/row";
|
||||
import Checkbox from "@docspace/components/checkbox";
|
||||
import Text from "@docspace/components/text";
|
||||
import UsersRow from "./UsersRow";
|
||||
import EmptyScreenUserReactSvgUrl from "PUBLIC_DIR/images/empty_screen_user.react.svg?url";
|
||||
import ClearEmptyFilterSvgUrl from "PUBLIC_DIR/images/clear.empty.filter.svg?url";
|
||||
|
||||
import { mockData } from "../../mockData";
|
||||
// import { mockData } from "../../mockData";
|
||||
|
||||
const StyledRowContainer = styled(RowContainer)`
|
||||
margin: 20px 0;
|
||||
|
||||
.clear-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.ec-desc {
|
||||
max-width: 348px;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledRow = styled(Row)`
|
||||
box-sizing: border-box;
|
||||
height: 40px;
|
||||
min-height: 40px;
|
||||
|
||||
.row-header-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.row-header-title {
|
||||
color: ${(props) => props.theme.client.settings.migration.tableHeaderText};
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@media ${tablet} {
|
||||
.row_content {
|
||||
height: auto;
|
||||
@ -37,10 +65,17 @@ const RowView = (props) => {
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
setSearchValue,
|
||||
} = props;
|
||||
const rowRef = useRef(null);
|
||||
|
||||
const toggleAll = (e) => toggleAllAccounts({ target: { checked: !e.target.checked } }, mockData);
|
||||
const toggleAll = (e) => toggleAllAccounts(e, users);
|
||||
|
||||
const handleToggle = (id) => toggleAccount(id);
|
||||
|
||||
const onClearFilter = () => {
|
||||
setSearchValue("");
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (viewAs !== "table" && viewAs !== "row") return;
|
||||
@ -50,32 +85,62 @@ const RowView = (props) => {
|
||||
} else {
|
||||
viewAs !== "table" && setViewAs("table");
|
||||
}
|
||||
|
||||
return cleanCheckedAccounts;
|
||||
}, [sectionWidth]);
|
||||
|
||||
return (
|
||||
<StyledRowContainer useReactWindow={false}>
|
||||
<StyledRow
|
||||
sectionWidth={sectionWidth}
|
||||
checkbox
|
||||
checked={checkedAccounts.length === mockData.length}
|
||||
onClick={toggleAll}
|
||||
indeterminate={checkedAccounts.length > 0 && checkedAccounts.length !== mockData.length}>
|
||||
<Text color="#a3a9ae" fontWeight={600} fontSize="12px">
|
||||
{t("Common:Name")}
|
||||
</Text>
|
||||
</StyledRow>
|
||||
{accountsData.map((data) => (
|
||||
<UsersRow
|
||||
t={t}
|
||||
key={data.id}
|
||||
data={data}
|
||||
sectionWidth={sectionWidth}
|
||||
toggleAccount={() => toggleAccount(data.id)}
|
||||
isChecked={isAccountChecked(data.id)}
|
||||
<StyledRowContainer forwardedRef={rowRef} useReactWindow={false}>
|
||||
{accountsData.length > 0 ? (
|
||||
<>
|
||||
<StyledRow sectionWidth={sectionWidth}>
|
||||
<div className="row-header-item">
|
||||
{checkedAccounts.length > 0 && (
|
||||
<Checkbox
|
||||
isChecked={checkedAccounts.length === users.length}
|
||||
isIndeterminate={isIndeterminate}
|
||||
onChange={toggleAll}
|
||||
/>
|
||||
)}
|
||||
<Text className="row-header-title">{t("Common:Name")}</Text>
|
||||
</div>
|
||||
</StyledRow>
|
||||
{accountsData.map((data) => (
|
||||
<UsersRow
|
||||
t={t}
|
||||
key={data.key}
|
||||
data={data}
|
||||
sectionWidth={sectionWidth}
|
||||
isChecked={isAccountChecked(data.key)}
|
||||
toggleAccount={() => handleToggle(data.key)}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreenContainer
|
||||
imageSrc={EmptyScreenUserReactSvgUrl}
|
||||
imageAlt="Empty Screen user image"
|
||||
headerText={t("People:NotFoundUsers")}
|
||||
descriptionText={t("People:NotFoundUsersDesc")}
|
||||
buttons={
|
||||
<Box displayProp="flex" alignItems="center">
|
||||
<IconButton
|
||||
className="clear-icon"
|
||||
isFill
|
||||
size="12"
|
||||
onClick={onClearFilter}
|
||||
iconName={ClearEmptyFilterSvgUrl}
|
||||
/>
|
||||
<Link
|
||||
type="action"
|
||||
isHovered={true}
|
||||
fontWeight="600"
|
||||
onClick={onClearFilter}
|
||||
>
|
||||
{t("Common:ClearFilter")}
|
||||
</Link>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
))}
|
||||
)}
|
||||
</StyledRowContainer>
|
||||
);
|
||||
};
|
||||
@ -87,7 +152,7 @@ export default inject(({ setup, importAccountsStore }) => {
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
setSearchValue,
|
||||
} = importAccountsStore;
|
||||
|
||||
return {
|
||||
@ -97,6 +162,6 @@ export default inject(({ setup, importAccountsStore }) => {
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
setSearchValue,
|
||||
};
|
||||
})(observer(RowView));
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import TableHeader from "@docspace/components/table-container/TableHeader";
|
||||
@ -80,8 +80,8 @@ const UsersTableHeader = (props) => {
|
||||
|
||||
setColumns((prevColumns) =>
|
||||
prevColumns.map((item, index) =>
|
||||
index === columnIndex ? { ...item, enable: !item.enable } : item,
|
||||
),
|
||||
index === columnIndex ? { ...item, enable: !item.enable } : item
|
||||
)
|
||||
);
|
||||
|
||||
const tableColumns = columns.map((c) => c.enable && c.key);
|
||||
|
@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import TableRow from "@docspace/components/table-container/TableRow";
|
||||
import TableCell from "@docspace/components/table-container/TableCell";
|
||||
import Text from "@docspace/components/text";
|
||||
@ -22,7 +21,16 @@ const StyledTableRow = styled(TableRow)`
|
||||
}
|
||||
`;
|
||||
|
||||
const UsersTableRow = ({ t, displayName, email, isDuplicate, isChecked, toggleAccount }) => {
|
||||
const NOT_EXIST = "—";
|
||||
|
||||
const UsersTableRow = ({
|
||||
t,
|
||||
displayName,
|
||||
email,
|
||||
isDuplicate,
|
||||
isChecked,
|
||||
toggleAccount,
|
||||
}) => {
|
||||
return (
|
||||
<StyledTableRow checked={isChecked} onClick={toggleAccount}>
|
||||
<TableCell>
|
||||
@ -33,7 +41,11 @@ const UsersTableRow = ({ t, displayName, email, isDuplicate, isChecked, toggleAc
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Text fontWeight={600} color="#a3a9ae" className="user-email textOverflow">
|
||||
<Text
|
||||
fontWeight={600}
|
||||
color="#a3a9ae"
|
||||
className="user-email textOverflow"
|
||||
>
|
||||
{email}
|
||||
</Text>
|
||||
</TableCell>
|
||||
@ -45,7 +57,7 @@ const UsersTableRow = ({ t, displayName, email, isDuplicate, isChecked, toggleAc
|
||||
</Text>
|
||||
) : (
|
||||
<Text fontWeight={600} color="#a3a9ae" className="textOverflow">
|
||||
-
|
||||
{NOT_EXIST}
|
||||
</Text>
|
||||
)}
|
||||
</TableCell>
|
||||
|
@ -4,11 +4,17 @@ import { isMobile } from "react-device-detect";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
import styled from "styled-components";
|
||||
|
||||
import EmptyScreenContainer from "@docspace/components/empty-screen-container";
|
||||
import IconButton from "@docspace/components/icon-button";
|
||||
import Link from "@docspace/components/link";
|
||||
import Box from "@docspace/components/box";
|
||||
import UsersTableHeader from "./UsersTableHeader";
|
||||
import UsersTableRow from "./UsersTableRow";
|
||||
import TableContainer from "@docspace/components/table-container/TableContainer";
|
||||
import TableBody from "@docspace/components/table-container/TableBody";
|
||||
import { mockData } from "../../mockData";
|
||||
import EmptyScreenUserReactSvgUrl from "PUBLIC_DIR/images/empty_screen_user.react.svg?url";
|
||||
import ClearEmptyFilterSvgUrl from "PUBLIC_DIR/images/clear.empty.filter.svg?url";
|
||||
// import { mockData } from "../../mockData";
|
||||
|
||||
const TABLE_VERSION = "6";
|
||||
const COLUMNS_SIZE = `nextcloudSecondColumnsSize_ver-${TABLE_VERSION}`;
|
||||
@ -29,9 +35,18 @@ const StyledTableContainer = styled(TableContainer)`
|
||||
margin-top: -1px;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: ${(props) => (props.theme.isBase ? "#F8F9F9" : "#282828")};
|
||||
background-color: ${(props) =>
|
||||
props.theme.isBase ? "#F8F9F9" : "#282828"};
|
||||
}
|
||||
}
|
||||
.clear-icon {
|
||||
margin-right: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.ec-desc {
|
||||
max-width: 618px;
|
||||
}
|
||||
`;
|
||||
|
||||
StyledTableContainer.defaultProps = { theme: Base };
|
||||
@ -39,6 +54,7 @@ StyledTableContainer.defaultProps = { theme: Base };
|
||||
const TableView = (props) => {
|
||||
const {
|
||||
t,
|
||||
users,
|
||||
userId,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
@ -48,17 +64,25 @@ const TableView = (props) => {
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
setSearchValue,
|
||||
} = props;
|
||||
const [hideColumns, setHideColumns] = useState(false);
|
||||
const tableRef = useRef(null);
|
||||
|
||||
const toggleAll = (e) => toggleAllAccounts(e, mockData);
|
||||
const toggleAll = (e) => toggleAllAccounts(e, users);
|
||||
|
||||
const handleToggle = (e, id) => {
|
||||
e.stopPropagation();
|
||||
toggleAccount(id);
|
||||
};
|
||||
|
||||
const onClearFilter = () => {
|
||||
setSearchValue("");
|
||||
};
|
||||
|
||||
const isIndeterminate =
|
||||
checkedAccounts.length > 0 && checkedAccounts.length !== users.length;
|
||||
|
||||
useEffect(() => {
|
||||
if (!sectionWidth) return;
|
||||
if (sectionWidth < 1025 || isMobile) {
|
||||
@ -66,8 +90,6 @@ const TableView = (props) => {
|
||||
} else {
|
||||
viewAs !== "table" && setViewAs("table");
|
||||
}
|
||||
|
||||
return cleanCheckedAccounts;
|
||||
}, [sectionWidth]);
|
||||
|
||||
const columnStorageName = `${COLUMNS_SIZE}=${userId}`;
|
||||
@ -75,40 +97,72 @@ const TableView = (props) => {
|
||||
|
||||
return (
|
||||
<StyledTableContainer forwardedRef={tableRef} useReactWindow>
|
||||
<UsersTableHeader
|
||||
t={t}
|
||||
sectionWidth={sectionWidth}
|
||||
tableRef={tableRef}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
setHideColumns={setHideColumns}
|
||||
isIndeterminate={checkedAccounts.length > 0 && checkedAccounts.length !== mockData.length}
|
||||
isChecked={checkedAccounts.length === mockData.length}
|
||||
toggleAll={toggleAll}
|
||||
/>
|
||||
<TableBody
|
||||
itemHeight={49}
|
||||
useReactWindow
|
||||
infoPanelVisible={false}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
filesLength={accountsData.length}
|
||||
hasMoreFiles={false}
|
||||
itemCount={accountsData.length}
|
||||
fetchMoreFiles={() => {}}>
|
||||
{accountsData.map((data) => (
|
||||
<UsersTableRow
|
||||
{accountsData.length > 0 ? (
|
||||
<>
|
||||
<UsersTableHeader
|
||||
t={t}
|
||||
key={data.id}
|
||||
displayName={data.displayName}
|
||||
email={data.email}
|
||||
isDuplicate={data.isDuplicate}
|
||||
hideColumns={hideColumns}
|
||||
isChecked={isAccountChecked(data.id)}
|
||||
toggleAccount={(e) => handleToggle(e, data.id)}
|
||||
sectionWidth={sectionWidth}
|
||||
tableRef={tableRef}
|
||||
userId={userId}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
setHideColumns={setHideColumns}
|
||||
isIndeterminate={isIndeterminate}
|
||||
isChecked={checkedAccounts.length === users.length}
|
||||
toggleAll={toggleAll}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableBody
|
||||
itemHeight={49}
|
||||
useReactWindow
|
||||
infoPanelVisible={false}
|
||||
columnStorageName={columnStorageName}
|
||||
columnInfoPanelStorageName={columnInfoPanelStorageName}
|
||||
filesLength={accountsData.length}
|
||||
hasMoreFiles={false}
|
||||
itemCount={accountsData.length}
|
||||
fetchMoreFiles={() => {}}
|
||||
>
|
||||
{accountsData.map((data) => (
|
||||
<UsersTableRow
|
||||
t={t}
|
||||
key={data.key}
|
||||
displayName={data.displayName}
|
||||
email={data.email}
|
||||
isDuplicate={data.isDuplicate}
|
||||
hideColumns={hideColumns}
|
||||
isChecked={isAccountChecked(data.key)}
|
||||
toggleAccount={(e) => handleToggle(e, data.key)}
|
||||
/>
|
||||
))}
|
||||
</TableBody>
|
||||
</>
|
||||
) : (
|
||||
<EmptyScreenContainer
|
||||
imageSrc={EmptyScreenUserReactSvgUrl}
|
||||
imageAlt="Empty Screen user image"
|
||||
headerText={t("People:NotFoundUsers")}
|
||||
descriptionText={t("People:NotFoundUsersDesc")}
|
||||
buttons={
|
||||
<Box displayProp="flex" alignItems="center">
|
||||
<IconButton
|
||||
className="clear-icon"
|
||||
isFill
|
||||
size="12"
|
||||
onClick={onClearFilter}
|
||||
iconName={ClearEmptyFilterSvgUrl}
|
||||
/>
|
||||
<Link
|
||||
type="action"
|
||||
isHovered={true}
|
||||
fontWeight="600"
|
||||
onClick={onClearFilter}
|
||||
>
|
||||
{t("Common:ClearFilter")}
|
||||
</Link>
|
||||
</Box>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</StyledTableContainer>
|
||||
);
|
||||
};
|
||||
@ -117,14 +171,16 @@ export default inject(({ setup, auth, importAccountsStore }) => {
|
||||
const { viewAs, setViewAs } = setup;
|
||||
const { id: userId } = auth.userStore.user;
|
||||
const {
|
||||
users,
|
||||
checkedAccounts,
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
setSearchValue,
|
||||
} = importAccountsStore;
|
||||
|
||||
return {
|
||||
users,
|
||||
viewAs,
|
||||
setViewAs,
|
||||
userId,
|
||||
@ -132,6 +188,6 @@ export default inject(({ setup, auth, importAccountsStore }) => {
|
||||
toggleAccount,
|
||||
toggleAllAccounts,
|
||||
isAccountChecked,
|
||||
cleanCheckedAccounts,
|
||||
setSearchValue,
|
||||
};
|
||||
})(observer(TableView));
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { Consumer } from "@docspace/components/utils/context";
|
||||
|
||||
import TableView from "./TableView";
|
||||
@ -13,9 +12,17 @@ const AccountsTable = (props) => {
|
||||
<Consumer>
|
||||
{(context) =>
|
||||
viewAs === "table" ? (
|
||||
<TableView sectionWidth={context.sectionWidth} accountsData={accountsData} t={t} />
|
||||
<TableView
|
||||
t={t}
|
||||
sectionWidth={context.sectionWidth}
|
||||
accountsData={accountsData}
|
||||
/>
|
||||
) : (
|
||||
<RowView sectionWidth={context.sectionWidth} accountsData={accountsData} t={t} />
|
||||
<RowView
|
||||
t={t}
|
||||
sectionWidth={context.sectionWidth}
|
||||
accountsData={accountsData}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</Consumer>
|
||||
@ -27,4 +34,4 @@ export default inject(({ setup }) => {
|
||||
return {
|
||||
viewAs,
|
||||
};
|
||||
})(observer(AccountsTable));
|
||||
})(withTranslation(["People"])(observer(AccountsTable)));
|
||||
|
@ -1,38 +1,57 @@
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
|
||||
import SearchInput from "@docspace/components/search-input";
|
||||
|
||||
import AccountsTable from "./AccountsTable";
|
||||
import AccountsPaging from "../../../sub-components/AccountsPaging";
|
||||
import UsersInfoBlock from "../../../sub-components/UsersInfoBlock";
|
||||
import Text from "@docspace/components/text";
|
||||
|
||||
import SearchInput from "@docspace/components/search-input";
|
||||
|
||||
import { Wrapper } from "../StyledStepper";
|
||||
|
||||
import UsersInfoBlock from "../../../sub-components/UsersInfoBlock";
|
||||
|
||||
import { mockData as nextStepData } from "../ThirdStep/mockData";
|
||||
import { mockData } from "./mockData";
|
||||
// import { mockData as nextStepData } from "../ThirdStep/mockData";
|
||||
// import { mockData } from "./mockData";
|
||||
import { NoEmailUsersBlock } from "../../../sub-components/NoEmailUsersBlock";
|
||||
|
||||
const LICENSE_LIMIT = 100;
|
||||
|
||||
const SecondStep = (props) => {
|
||||
const { t, incrementStep, decrementStep, numberOfCheckedAccounts } = props;
|
||||
const {
|
||||
t,
|
||||
incrementStep,
|
||||
decrementStep,
|
||||
numberOfCheckedAccounts,
|
||||
users,
|
||||
searchValue,
|
||||
setSearchValue,
|
||||
} = props;
|
||||
|
||||
const [dataPortion, setDataPortion] = useState(mockData.slice(0, 25));
|
||||
const [dataPortion, setDataPortion] = useState(users.slice(0, 25));
|
||||
|
||||
const handleDataChange = (leftBoundary, rightBoundary) => {
|
||||
setDataPortion(mockData.slice(leftBoundary, rightBoundary));
|
||||
setDataPortion(users.slice(leftBoundary, rightBoundary));
|
||||
};
|
||||
|
||||
const onChangeInput = (value) => {
|
||||
setSearchValue(value);
|
||||
};
|
||||
|
||||
const onClearSearchInput = () => {
|
||||
setSearchValue("");
|
||||
};
|
||||
|
||||
const filteredAccounts = dataPortion.filter(
|
||||
(data) =>
|
||||
data.displayName.toLowerCase().startsWith(searchValue.toLowerCase()) ||
|
||||
data.email.toLowerCase().startsWith(searchValue.toLowerCase())
|
||||
);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{nextStepData.length > 0 && <NoEmailUsersBlock users={nextStepData.length} t={t} />}
|
||||
{users.length > 0 && <NoEmailUsersBlock users={users.length} t={t} />}
|
||||
|
||||
{mockData.length > 0 ? (
|
||||
{users.length > 0 ? (
|
||||
<>
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
@ -48,23 +67,25 @@ const SecondStep = (props) => {
|
||||
<UsersInfoBlock
|
||||
t={t}
|
||||
selectedUsers={numberOfCheckedAccounts}
|
||||
totalUsers={mockData.length}
|
||||
totalUsers={users.length}
|
||||
totalLicenceLimit={LICENSE_LIMIT}
|
||||
/>
|
||||
|
||||
<SearchInput
|
||||
id="search-users-input"
|
||||
onChange={() => console.log("changed")}
|
||||
onClearSearch={() => console.log("cleared")}
|
||||
placeholder={t("Common:Search")}
|
||||
value={searchValue}
|
||||
onChange={onChangeInput}
|
||||
refreshTimeout={100}
|
||||
onClearSearch={onClearSearchInput}
|
||||
/>
|
||||
|
||||
<AccountsTable accountsData={dataPortion} t={t} />
|
||||
<AccountsTable t={t} accountsData={filteredAccounts} />
|
||||
|
||||
{mockData.length > 25 && (
|
||||
{users.length > 25 && (
|
||||
<AccountsPaging
|
||||
t={t}
|
||||
numberOfItems={mockData.length}
|
||||
numberOfItems={users.length}
|
||||
setDataPortion={handleDataChange}
|
||||
/>
|
||||
)}
|
||||
@ -75,26 +96,30 @@ const SecondStep = (props) => {
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
onSaveClick={incrementStep}
|
||||
onCancelClick={decrementStep}
|
||||
saveButtonLabel={t("Settings:NextStep")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
showReminder
|
||||
displaySettings
|
||||
saveButtonDisabled={numberOfCheckedAccounts > LICENSE_LIMIT}
|
||||
/>
|
||||
{filteredAccounts.length > 0 && (
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
onSaveClick={incrementStep}
|
||||
onCancelClick={decrementStep}
|
||||
saveButtonLabel={t("Settings:NextStep")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
showReminder
|
||||
displaySettings
|
||||
saveButtonDisabled={numberOfCheckedAccounts > LICENSE_LIMIT}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ setup, importAccountsStore }) => {
|
||||
const { viewAs } = setup;
|
||||
const { numberOfCheckedAccounts } = importAccountsStore;
|
||||
export default inject(({ importAccountsStore }) => {
|
||||
const { numberOfCheckedAccounts, users, searchValue, setSearchValue } =
|
||||
importAccountsStore;
|
||||
|
||||
return {
|
||||
viewAs,
|
||||
numberOfCheckedAccounts,
|
||||
users,
|
||||
searchValue,
|
||||
setSearchValue,
|
||||
};
|
||||
})(observer(SecondStep));
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import styled from "styled-components";
|
||||
|
||||
import Button from "@docspace/components/button";
|
||||
import Text from "@docspace/components/text";
|
||||
@ -18,18 +19,52 @@ const ButtonsWrapper = styled.div`
|
||||
column-gap: 8px;
|
||||
`;
|
||||
|
||||
const SeventhStep = ({ t }) => {
|
||||
const SeventhStep = ({
|
||||
t,
|
||||
selectedUsers,
|
||||
importedUsers,
|
||||
getMigrationLog,
|
||||
cleanCheckedAccounts,
|
||||
sendWelcomeLetter,
|
||||
}) => {
|
||||
const [isChecked, setIsChecked] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onDownloadLog = async () => {
|
||||
try {
|
||||
await getMigrationLog()
|
||||
.then((response) => new Blob([response]))
|
||||
.then((blob) => {
|
||||
let a = document.createElement("a");
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
a.href = url;
|
||||
a.download = "migration.log";
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
});
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
const onChangeCheckbox = () => {
|
||||
setIsChecked((prev) => !prev);
|
||||
};
|
||||
|
||||
const onFinishClick = () => {
|
||||
if (isChecked) {
|
||||
sendWelcomeLetter({ isSendWelcomeEmail: true });
|
||||
}
|
||||
setTimeout(() => {
|
||||
navigate(-1);
|
||||
cleanCheckedAccounts();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Text fontSize="12px">
|
||||
{t("Settings:ImportedUsers", { selectedUsers: 67, importedUsers: 70 })}
|
||||
{t("Settings:ImportedUsers", { selectedUsers, importedUsers })}
|
||||
</Text>
|
||||
<Text fontSize="12px" color="#F21C0E" className="mt-8">
|
||||
{t("Settings:ErrorsWereFound", { errors: 3 })}
|
||||
@ -45,17 +80,43 @@ const SeventhStep = ({ t }) => {
|
||||
place="right"
|
||||
offsetRight={0}
|
||||
style={{ marginLeft: "4px" }}
|
||||
tooltipContent={<Text fontSize="12px">{t("Settings:WelcomeLetterTooltip")}</Text>}
|
||||
tooltipContent={
|
||||
<Text fontSize="12px">{t("Settings:WelcomeLetterTooltip")}</Text>
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<ButtonsWrapper>
|
||||
<Button size="small" label={t("Common:Finish")} primary onClick={() => navigate(-1)} />
|
||||
<Button size="small" label={t("Settings:DownloadLog")} />
|
||||
<Button size="small" label={t("Settings:DeleteTemporaryFile")} />
|
||||
<Button
|
||||
size="small"
|
||||
label={t("Common:Finish")}
|
||||
primary
|
||||
onClick={onFinishClick}
|
||||
/>
|
||||
<Button
|
||||
size="small"
|
||||
label={t("Settings:DownloadLog")}
|
||||
onClick={onDownloadLog}
|
||||
/>
|
||||
</ButtonsWrapper>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SeventhStep;
|
||||
export default inject(({ importAccountsStore }) => {
|
||||
const {
|
||||
users,
|
||||
getMigrationLog,
|
||||
numberOfCheckedAccounts,
|
||||
cleanCheckedAccounts,
|
||||
sendWelcomeLetter,
|
||||
} = importAccountsStore;
|
||||
|
||||
return {
|
||||
importedUsers: users.length,
|
||||
selectedUsers: numberOfCheckedAccounts,
|
||||
getMigrationLog,
|
||||
cleanCheckedAccounts,
|
||||
sendWelcomeLetter,
|
||||
};
|
||||
})(observer(SeventhStep));
|
||||
|
@ -1,67 +1,88 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
|
||||
import SaveCancelButtons from "@docspace/components/save-cancel-buttons";
|
||||
import ProgressBar from "@docspace/components/progress-bar";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { CancelUploadDialog } from "SRC_DIR/components/dialogs";
|
||||
import Button from "@docspace/components/button";
|
||||
|
||||
import { Wrapper } from "../StyledStepper";
|
||||
|
||||
const SixthStep = ({ t, incrementStep, decrementStep }) => {
|
||||
const [isCancelVisible, setIsCancelVisible] = useState(false);
|
||||
import ProgressBar from "@docspace/components/progress-bar";
|
||||
import Button from "@docspace/components/button";
|
||||
|
||||
const PERCENT_STEP = 5;
|
||||
|
||||
const SixthStep = ({
|
||||
t,
|
||||
incrementStep,
|
||||
isSixthStep,
|
||||
setIsLoading,
|
||||
migrationFile,
|
||||
cancelMigration,
|
||||
data,
|
||||
toggles,
|
||||
}) => {
|
||||
const [isVisble, setIsVisble] = useState(false);
|
||||
const [percent, setPercent] = useState(0);
|
||||
const percentRef = useRef(0);
|
||||
|
||||
const PERCENT_STEP = 5;
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
if (percentRef.current < 100) {
|
||||
setPercent((prevPercent) => prevPercent + PERCENT_STEP);
|
||||
percentRef.current += PERCENT_STEP;
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
incrementStep();
|
||||
}
|
||||
}, 200);
|
||||
|
||||
return () => {
|
||||
clearInterval(interval);
|
||||
};
|
||||
try {
|
||||
const interval = setInterval(() => {
|
||||
if (percentRef.current < 100) {
|
||||
setIsLoading(true);
|
||||
setPercent((prev) => prev + PERCENT_STEP);
|
||||
percentRef.current += PERCENT_STEP;
|
||||
} else {
|
||||
clearInterval(interval);
|
||||
setIsLoading(false);
|
||||
incrementStep();
|
||||
}
|
||||
}, 1000);
|
||||
migrationFile({ ...data, ...toggles });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onClickButton = () => {
|
||||
setIsCancelVisible(true);
|
||||
const onCancel = () => {
|
||||
setIsVisble(true);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
{percent < 102 ? (
|
||||
{percent < 102 && (
|
||||
<>
|
||||
<ProgressBar percent={percent} className="data-import-progress-bar" />
|
||||
<Button size="small" label={t("Common:CancelButton")} onClick={onClickButton} />
|
||||
<Button
|
||||
size="small"
|
||||
className="cancel-button"
|
||||
label={t("Common:CancelButton")}
|
||||
onClick={onCancel}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<SaveCancelButtons
|
||||
className="save-cancel-buttons"
|
||||
onSaveClick={incrementStep}
|
||||
onCancelClick={decrementStep}
|
||||
saveButtonLabel={t("Settings:NextStep")}
|
||||
cancelButtonLabel={t("Common:Back")}
|
||||
displaySettings
|
||||
showReminder
|
||||
/>
|
||||
)}
|
||||
|
||||
{isCancelVisible && (
|
||||
{isVisble && (
|
||||
<CancelUploadDialog
|
||||
visible={isCancelVisible}
|
||||
visible={isVisble}
|
||||
loading={false}
|
||||
onClose={() => setIsCancelVisible(false)}
|
||||
isSixthStep={isSixthStep}
|
||||
cancelMigration={cancelMigration}
|
||||
onClose={() => setIsVisble(false)}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default SixthStep;
|
||||
export default inject(({ importAccountsStore }) => {
|
||||
const { data, setIsLoading, migrationFile, cancelMigration, toggles } =
|
||||
importAccountsStore;
|
||||
|
||||
return {
|
||||
data,
|
||||
toggles,
|
||||
setIsLoading,
|
||||
migrationFile,
|
||||
cancelMigration,
|
||||
};
|
||||
})(observer(SixthStep));
|
||||
|
@ -10,6 +10,8 @@ import HelpButton from "@docspace/components/help-button";
|
||||
import Text from "@docspace/components/text";
|
||||
|
||||
export const getStepsData = (t, currentStep, setCurrentStep) => {
|
||||
const isSixthStep = currentStep === 6;
|
||||
|
||||
const incrementStep = () => {
|
||||
if (currentStep !== 6) {
|
||||
setCurrentStep((prev) => prev + 1);
|
||||
@ -26,17 +28,35 @@ export const getStepsData = (t, currentStep, setCurrentStep) => {
|
||||
{
|
||||
title: t("Common:SelectFile"),
|
||||
description: t("Settings:SelectFileDescriptionNextcloud"),
|
||||
component: <FirstStep t={t} incrementStep={incrementStep} decrementStep={decrementStep} />,
|
||||
component: (
|
||||
<FirstStep
|
||||
t={t}
|
||||
incrementStep={incrementStep}
|
||||
decrementStep={decrementStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("Settings:SelectUsers"),
|
||||
description: t("Settings:SelectUsersDescriptionNextcloud"),
|
||||
component: <SecondStep t={t} incrementStep={incrementStep} decrementStep={decrementStep} />,
|
||||
component: (
|
||||
<SecondStep
|
||||
t={t}
|
||||
incrementStep={incrementStep}
|
||||
decrementStep={decrementStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("Settings:AddEmails"),
|
||||
description: t("Settings:SelectUsersDescriptionNextcloud"),
|
||||
component: <ThirdStep t={t} incrementStep={incrementStep} decrementStep={decrementStep} />,
|
||||
component: (
|
||||
<ThirdStep
|
||||
t={t}
|
||||
incrementStep={incrementStep}
|
||||
decrementStep={decrementStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("Settings:SelectUserTypes"),
|
||||
@ -56,22 +76,47 @@ export const getStepsData = (t, currentStep, setCurrentStep) => {
|
||||
/>
|
||||
</>
|
||||
),
|
||||
component: <FourthStep t={t} incrementStep={incrementStep} decrementStep={decrementStep} />,
|
||||
component: (
|
||||
<FourthStep
|
||||
t={t}
|
||||
incrementStep={incrementStep}
|
||||
decrementStep={decrementStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("Settings:DataImport"),
|
||||
description: t("Settings:ImportSectionDescription"),
|
||||
component: <FifthStep t={t} incrementStep={incrementStep} decrementStep={decrementStep} />,
|
||||
component: (
|
||||
<FifthStep
|
||||
t={t}
|
||||
incrementStep={incrementStep}
|
||||
decrementStep={decrementStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("Settings:DataImportProcessing"),
|
||||
description: t("Settings:ImportProcessingDescription"),
|
||||
component: <SixthStep t={t} incrementStep={incrementStep} decrementStep={decrementStep} />,
|
||||
component: (
|
||||
<SixthStep
|
||||
t={t}
|
||||
incrementStep={incrementStep}
|
||||
decrementStep={decrementStep}
|
||||
isSixthStep={isSixthStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("Settings:DataImportComplete"),
|
||||
description: t("Settings:ImportCompleteDescriptionNextcloud"),
|
||||
component: <SeventhStep t={t} incrementStep={incrementStep} decrementStep={decrementStep} />,
|
||||
component: (
|
||||
<SeventhStep
|
||||
t={t}
|
||||
incrementStep={incrementStep}
|
||||
decrementStep={decrementStep}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
};
|
||||
|
@ -1,13 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import styled from "styled-components";
|
||||
|
||||
import Text from "@docspace/components/text";
|
||||
|
||||
import { isMobileOnly } from "react-device-detect";
|
||||
import BreakpointWarning from "SRC_DIR/components/BreakpointWarning";
|
||||
|
||||
import { getStepsData } from "./Stepper";
|
||||
|
||||
const NextcloudWrapper = styled.div`
|
||||
@ -30,12 +28,11 @@ const NextcloudWrapper = styled.div`
|
||||
|
||||
const NextcloudWorkspace = (props) => {
|
||||
const { t, tReady, theme } = props;
|
||||
|
||||
const [currentStep, setCurrentStep] = useState(0);
|
||||
|
||||
const StepsData = getStepsData(t, currentStep, setCurrentStep);
|
||||
|
||||
if (isMobileOnly) return <BreakpointWarning sectionName={t("Settings:DataImport")} />;
|
||||
if (isMobileOnly)
|
||||
return <BreakpointWarning sectionName={t("Settings:DataImport")} />;
|
||||
|
||||
if (!tReady) return;
|
||||
|
||||
@ -45,13 +42,21 @@ const NextcloudWorkspace = (props) => {
|
||||
<Text
|
||||
className="data-import-description"
|
||||
lineHeight="20px"
|
||||
color={theme.isBase ? "#657077" : "#ADADAD"}>
|
||||
color={theme.isBase ? "#657077" : "#ADADAD"}
|
||||
>
|
||||
{t("Settings:AboutDataImport")}
|
||||
</Text>
|
||||
<Text className="data-import-counter" fontSize="16px" fontWeight={700} lineHeight="22px">
|
||||
<Text
|
||||
className="data-import-counter"
|
||||
fontSize="16px"
|
||||
fontWeight={700}
|
||||
lineHeight="22px"
|
||||
>
|
||||
{currentStep + 1}/{StepsData.length}. {StepsData[currentStep].title}
|
||||
</Text>
|
||||
<div className="data-import-section-description">{StepsData[currentStep].description}</div>
|
||||
<div className="data-import-section-description">
|
||||
{StepsData[currentStep].description}
|
||||
</div>
|
||||
</NextcloudWrapper>
|
||||
{StepsData[currentStep].component}
|
||||
</>
|
||||
@ -64,4 +69,8 @@ export default inject(({ setup, auth }) => {
|
||||
initSettings,
|
||||
theme: auth.settingsStore.theme,
|
||||
};
|
||||
})(withTranslation(["Common, Settings, SMTPSettings"])(observer(NextcloudWorkspace)));
|
||||
})(
|
||||
withTranslation(["Common, Settings, SMTPSettings"])(
|
||||
observer(NextcloudWorkspace)
|
||||
)
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user