Merge branch 'develop' into bugfix/thirdparty
This commit is contained in:
commit
bf963f511b
@ -60,6 +60,8 @@ servers_products_name_backend=(ASC.CRM)
|
||||
servers_products_name_backend+=(ASC.Files)
|
||||
servers_products_name_backend+=(ASC.People)
|
||||
servers_products_name_backend+=(ASC.Projects)
|
||||
servers_products_name_backend+=(ASC.Calendar)
|
||||
servers_products_name_backend+=(ASC.Mail)
|
||||
|
||||
# Publish server backend products
|
||||
for i in ${!servers_products_name_backend[@]}; do
|
||||
|
@ -47,10 +47,12 @@
|
||||
# service host #
|
||||
API_SYSTEM_HOST=${CONTAINER_PREFIX}api-system
|
||||
BACKUP_HOST=${CONTAINER_PREFIX}backup
|
||||
CALENDAR_HOST=${CONTAINER_PREFIX}calendar
|
||||
CRM_HOST=${CONTAINER_PREFIX}crm
|
||||
STORAGE_ENCRYPTION_HOST=${CONTAINER_PREFIX}storage-encryption
|
||||
FILES_HOST=${CONTAINER_PREFIX}files
|
||||
FILES_SERVICES_HOST=${CONTAINER_PREFIX}files-services
|
||||
MAIL_HOST=${CONTAINER_PREFIX}mail
|
||||
STORAGE_MIGRATION_HOST=${CONTAINER_PREFIX}storage-migration
|
||||
NOTIFY_HOST=${CONTAINER_PREFIX}notify
|
||||
PEOPLE_SERVER_HOST=${CONTAINER_PREFIX}people-server
|
||||
@ -68,9 +70,11 @@
|
||||
SERVICE_API_SYSTEM=${API_SYSTEM_HOST}:${SERVICE_PORT}
|
||||
SERVICE_BACKUP=${BACKUP_HOST}:${SERVICE_PORT}
|
||||
SERVICE_CRM=${CRM_HOST}:${SERVICE_PORT}
|
||||
SERVICE_CALENDAR=${CALENDAR_HOST}:${SERVICE_PORT}
|
||||
SERVICE_STORAGE_ENCRYPTION=${STORAGE_ENCRYPTION_HOST}:${SERVICE_PORT}
|
||||
SERVICE_FILES=${FILES_HOST}:${SERVICE_PORT}
|
||||
SERVICE_FILES_SERVICES=${FILES_SERVICES_HOST}:${SERVICE_PORT}
|
||||
SERVICE_MAIL=${MAIL_HOST}:${SERVICE_PORT}
|
||||
SERVICE_STORAGE_MIGRATION=${STORAGE_MIGRATION_HOST}:${SERVICE_PORT}
|
||||
SERVICE_NOTIFY=${NOTIFY_HOST}:${SERVICE_PORT}
|
||||
SERVICE_PEOPLE_SERVER=${PEOPLE_SERVER_HOST}:${SERVICE_PORT}
|
||||
|
@ -45,11 +45,8 @@ RUN echo "nameserver 8.8.8.8" | tee /etc/resolv.conf > /dev/null && \
|
||||
bash build-frontend.sh -sp ${SRC_PATH} && \
|
||||
bash build-backend.sh -sp ${SRC_PATH} -ar "--disable-parallel" && \
|
||||
bash publish-backend.sh -sp ${SRC_PATH} -bp ${BUILD_PATH} -ar "--disable-parallel"
|
||||
|
||||
COPY config/mysql/conf.d/mysql.cnf /etc/mysql/conf.d/mysql.cnf
|
||||
COPY config/supervisor/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
RUN sed -i 's/Server=.*;Port=/Server=127.0.0.1;Port=/' /app/onlyoffice/config/appsettings.test.json
|
||||
COPY config/mysql/conf.d/mysql.cnf /etc/mysql/conf.d/mysql.cnf
|
||||
|
||||
RUN rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@ -107,6 +104,8 @@ COPY --from=base ${SRC_PATH}/web/ASC.Web.Login/dist ${BUILD_PATH}/studio/login
|
||||
COPY --from=base ${SRC_PATH}/products/ASC.People/Client/dist ${BUILD_PATH}/products/ASC.People/client
|
||||
COPY --from=base ${SRC_PATH}/products/ASC.Projects/Client/dist ${BUILD_PATH}/products/ASC.Projects/client
|
||||
COPY --from=base ${SRC_PATH}/web/ASC.Web.Client/dist ${BUILD_PATH}/studio/client
|
||||
COPY --from=base ${SRC_PATH}/products/ASC.Calendar/Client/dist ${BUILD_PATH}/products/ASC.Calendar/client
|
||||
COPY --from=base ${SRC_PATH}/products/ASC.Mail/Client/dist ${BUILD_PATH}/products/ASC.Mail/client
|
||||
|
||||
COPY /config/nginx/templates/upstream.conf.template /etc/nginx/templates/upstream.conf.template
|
||||
|
||||
@ -122,6 +121,8 @@ RUN chown nginx:nginx /etc/nginx/* -R && \
|
||||
sed -i 's/localhost:5020/$service_projects_server/' /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
sed -i 's/localhost:5000/$service_api/' /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
sed -i 's/localhost:5003/$service_studio/' /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
sed -i 's/localhost:5023/$service_calendar/' /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
sed -i 's/localhost:5022/$service_mail/' /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
sed -i 's/localhost:9999/$service_urlshortener/' /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
sed -i 's/172.*/$document_server;/' /etc/nginx/conf.d/onlyoffice.conf && \
|
||||
# configute the image nginx whith less privileged https://hub.docker.com/_/nginx
|
||||
@ -146,6 +147,15 @@ COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Data.B
|
||||
|
||||
CMD ["ASC.Data.Backup.dll", "ASC.Data.Backup", "core:products:folder=/var/www/products/", "core:products:subfolder=server"]
|
||||
|
||||
## ASC.Calendar ##
|
||||
FROM builder AS calendar
|
||||
WORKDIR ${BUILD_PATH}/products/ASC.Calendar/server/
|
||||
|
||||
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.sh .
|
||||
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/products/ASC.Calendar/server/ .
|
||||
|
||||
CMD ["ASC.Calendar.dll", "ASC.Calendar"]
|
||||
|
||||
## ASC.CRM ##
|
||||
FROM builder AS crm
|
||||
WORKDIR ${BUILD_PATH}/products/ASC.CRM/server/
|
||||
@ -182,6 +192,15 @@ COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/services/ASC.Files.
|
||||
|
||||
CMD ["ASC.Files.Service.dll", "ASC.Files.Service", "core:products:folder=/var/www/products/", "core:products:subfolder=server"]
|
||||
|
||||
## ASC.Mail ##
|
||||
FROM builder AS mail
|
||||
WORKDIR ${BUILD_PATH}/products/ASC.Mail/server/
|
||||
|
||||
COPY --chown=onlyoffice:onlyoffice docker-entrypoint.sh .
|
||||
COPY --from=base --chown=onlyoffice:onlyoffice ${BUILD_PATH}/products/ASC.Mail/server/ .
|
||||
|
||||
CMD ["ASC.Mail.dll", "ASC.Mail"]
|
||||
|
||||
## ASC.Data.Storage.Migration ##
|
||||
FROM builder AS data_storage_migration
|
||||
WORKDIR ${BUILD_PATH}/services/storage.migration/service/
|
||||
|
@ -29,6 +29,9 @@ x-service:
|
||||
- people_data:/var/www/products/ASC.People/server/
|
||||
- crm_data:/var/www/products/ASC.CRM/server/
|
||||
- project_data:/var/www/products/ASC.Projects/server/
|
||||
- calendar_data:/var/www/products/ASC.Calendar/server/
|
||||
- mail_data:/var/www/products/ASC.Mail/server/
|
||||
|
||||
|
||||
services:
|
||||
onlyoffice-elasticsearch:
|
||||
@ -95,6 +98,11 @@ services:
|
||||
image: "${REPO}/${STATUS}appserver-backup:${SRV_VERSION}"
|
||||
container_name: ${BACKUP_HOST}
|
||||
|
||||
onlyoffice-calendar:
|
||||
<<: *x-service-base
|
||||
image: "${REPO}/${STATUS}appserver-calendar:${SRV_VERSION}"
|
||||
container_name: ${CALENDAR_HOST}
|
||||
|
||||
onlyoffice-crm:
|
||||
<<: *x-service-base
|
||||
image: "${REPO}/${STATUS}appserver-crm:${SRV_VERSION}"
|
||||
@ -115,6 +123,11 @@ services:
|
||||
image: "${REPO}/${STATUS}appserver-files-services:${SRV_VERSION}"
|
||||
container_name: ${FILES_SERVICES_HOST}
|
||||
|
||||
onlyoffice-mail:
|
||||
<<: *x-service-base
|
||||
image: "${REPO}/${STATUS}appserver-mail:${SRV_VERSION}"
|
||||
container_name: ${MAIL_HOST}
|
||||
|
||||
onlyoffice-storage-migration:
|
||||
<<: *x-service-base
|
||||
image: "${REPO}/${STATUS}appserver-storage-migration:${SRV_VERSION}"
|
||||
@ -187,10 +200,12 @@ services:
|
||||
depends_on:
|
||||
- onlyoffice-api-system
|
||||
- onlyoffice-backup
|
||||
- onlyoffice-calendar
|
||||
- onlyoffice-crm
|
||||
- onlyoffice-storage-encryption
|
||||
- onlyoffice-files
|
||||
- onlyoffice-files-services
|
||||
- onlyoffice-mail
|
||||
- onlyoffice-storage-migration
|
||||
- onlyoffice-people-server
|
||||
- onlyoffice-projects-server
|
||||
@ -204,10 +219,12 @@ services:
|
||||
environment:
|
||||
- SERVICE_API_SYSTEM=${SERVICE_API_SYSTEM}
|
||||
- SERVICE_BACKUP=${SERVICE_BACKUP}
|
||||
- SERVICE_CALENDAR=${SERVICE_CALENDAR}
|
||||
- SERVICE_CRM=${SERVICE_CRM}
|
||||
- SERVICE_STORAGE_ENCRYPTION=${SERVICE_STORAGE_ENCRYPTION}
|
||||
- SERVICE_FILES=${SERVICE_FILES}
|
||||
- SERVICE_FILES_SERVICES=${SERVICE_FILES_SERVICES}
|
||||
- SERVICE_MAIL=${SERVICE_MAIL}
|
||||
- SERVICE_STORAGE_MIGRATION=${SERVICE_STORAGE_MIGRATION}
|
||||
- SERVICE_NOTIFY=${SERVICE_NOTIFY}
|
||||
- SERVICE_PEOPLE_SERVER=${SERVICE_PEOPLE_SERVER}
|
||||
@ -240,3 +257,5 @@ volumes:
|
||||
people_data:
|
||||
crm_data:
|
||||
project_data:
|
||||
calendar_data:
|
||||
mail_data:
|
||||
|
@ -15,6 +15,13 @@ services:
|
||||
target: backup
|
||||
image: "${REPO}/${STATUS}appserver-backup:${SRV_VERSION}"
|
||||
|
||||
onlyoffice-calendar:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: "${DOCKERFILE}"
|
||||
target: calendar
|
||||
image: "${REPO}/${STATUS}appserver-calendar:${SRV_VERSION}"
|
||||
|
||||
onlyoffice-crm:
|
||||
build:
|
||||
context: ./
|
||||
@ -43,6 +50,13 @@ services:
|
||||
target: files_services
|
||||
image: "${REPO}/${STATUS}appserver-files-services:${SRV_VERSION}"
|
||||
|
||||
onlyoffice-mail:
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: "${DOCKERFILE}"
|
||||
target: mail
|
||||
image: "${REPO}/${STATUS}appserver-mail:${SRV_VERSION}"
|
||||
|
||||
onlyoffice-storage-migration:
|
||||
build:
|
||||
context: ./
|
||||
|
@ -10,6 +10,11 @@ map $SERVICE_BACKUP $service_backup {
|
||||
$SERVICE_BACKUP $SERVICE_BACKUP;
|
||||
}
|
||||
|
||||
map $SERVICE_CALENDAR $service_calendar {
|
||||
volatile;
|
||||
$SERVICE_CALENDAR $SERVICE_CALENDAR;
|
||||
}
|
||||
|
||||
map $SERVICE_CRM $service_crm {
|
||||
volatile;
|
||||
$SERVICE_CRM $SERVICE_CRM;
|
||||
@ -30,6 +35,11 @@ map $SERVICE_FILES_SERVICES $service_files_services {
|
||||
$SERVICE_FILES_SERVICES $SERVICE_FILES_SERVICES;
|
||||
}
|
||||
|
||||
map $SERVICE_MAIL $service_mail {
|
||||
volatile;
|
||||
$SERVICE_MAIL $SERVICE_MAIL;
|
||||
}
|
||||
|
||||
map $SERVICE_STORAGE_MIGRATION $service_storage_migration {
|
||||
volatile;
|
||||
$SERVICE_STORAGE_MIGRATION $SERVICE_STORAGE_MIGRATION;
|
||||
|
@ -29,6 +29,8 @@ x-service:
|
||||
- people_data:/var/www/products/ASC.People/server/
|
||||
- crm_data:/var/www/products/ASC.CRM/server/
|
||||
- project_data:/var/www/products/ASC.Projects/server/
|
||||
- calendar_data:/var/www/products/ASC.Calendar/server/
|
||||
- mail_data:/var/www/products/ASC.Mail/server/
|
||||
|
||||
services:
|
||||
onlyoffice-notify:
|
||||
@ -47,3 +49,5 @@ volumes:
|
||||
people_data:
|
||||
crm_data:
|
||||
project_data:
|
||||
calendar_data:
|
||||
mail_data:
|
||||
|
@ -11,7 +11,6 @@ const Badge = (props) => {
|
||||
if (!props.onClick) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
props.onClick(e);
|
||||
};
|
||||
|
||||
|
@ -80,8 +80,8 @@ class ContextMenuButton extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
onIconButtonClick = () => {
|
||||
if (this.props.isDisabled) {
|
||||
onIconButtonClick = (e) => {
|
||||
if (this.props.isDisabled || this.props.isNew) {
|
||||
this.stopAction;
|
||||
return;
|
||||
}
|
||||
@ -95,7 +95,7 @@ class ContextMenuButton extends React.Component {
|
||||
!this.props.isDisabled &&
|
||||
this.state.isOpen &&
|
||||
this.props.onClick &&
|
||||
this.props.onClick()
|
||||
this.props.onClick(e)
|
||||
); // eslint-disable-line react/prop-types
|
||||
};
|
||||
|
||||
@ -125,12 +125,17 @@ class ContextMenuButton extends React.Component {
|
||||
}
|
||||
|
||||
callNewMenu = (e) => {
|
||||
if (this.props.isDisabled) {
|
||||
if (this.props.isDisabled || !this.props.isNew) {
|
||||
this.stopAction;
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.isNew && this.props.onClick(e);
|
||||
this.setState(
|
||||
{
|
||||
data: this.props.getData(),
|
||||
},
|
||||
() => this.props.onClick(e)
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
@ -12,9 +12,9 @@ import "./custom.scss";
|
||||
import i18n from "./i18n";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
import { regDesktop } from "@appserver/common/desktop";
|
||||
import Home from "./components/pages/Home";
|
||||
import Settings from "./components/pages/Settings";
|
||||
import VersionHistory from "./components/pages/VersionHistory";
|
||||
import Home from "./pages/Home";
|
||||
import Settings from "./pages/Settings";
|
||||
import VersionHistory from "./pages/VersionHistory";
|
||||
import ErrorBoundary from "@appserver/common/components/ErrorBoundary";
|
||||
import Panels from "./components/FilesPanels";
|
||||
import { AppServerConfig } from "@appserver/common/constants";
|
||||
|
269
products/ASC.Files/Client/src/HOCs/withBadges.js
Normal file
269
products/ASC.Files/Client/src/HOCs/withBadges.js
Normal file
@ -0,0 +1,269 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import {
|
||||
ShareAccessRights,
|
||||
AppServerConfig,
|
||||
} from "@appserver/common/constants";
|
||||
import toastr from "studio/toastr";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import {
|
||||
convertFile,
|
||||
getFileConversationProgress,
|
||||
} from "@appserver/common/api/files";
|
||||
|
||||
import Badges from "../components/Badges";
|
||||
import config from "../../package.json";
|
||||
|
||||
export default function withBadges(WrappedComponent) {
|
||||
class WithBadges extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { showConvertDialog: false };
|
||||
}
|
||||
onClickLock = () => {
|
||||
const { item, lockFileAction } = this.props;
|
||||
const { locked, id } = item;
|
||||
|
||||
lockFileAction(id, !locked).catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
onClickFavorite = () => {
|
||||
const { t, item, setFavoriteAction } = this.props;
|
||||
|
||||
setFavoriteAction("remove", item.id)
|
||||
.then(() => toastr.success(t("RemovedFromFavorites")))
|
||||
.catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
onShowVersionHistory = () => {
|
||||
const {
|
||||
homepage,
|
||||
isTabletView,
|
||||
item,
|
||||
setIsVerHistoryPanel,
|
||||
fetchFileVersions,
|
||||
history,
|
||||
isTrashFolder,
|
||||
} = this.props;
|
||||
if (isTrashFolder) return;
|
||||
|
||||
if (!isTabletView) {
|
||||
fetchFileVersions(item.id + "");
|
||||
setIsVerHistoryPanel(true);
|
||||
} else {
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, homepage, `/${item.id}/history`)
|
||||
);
|
||||
}
|
||||
};
|
||||
onBadgeClick = () => {
|
||||
const {
|
||||
item,
|
||||
selectedFolderPathParts,
|
||||
markAsRead,
|
||||
setNewFilesPanelVisible,
|
||||
setNewFilesIds,
|
||||
updateRootBadge,
|
||||
updateFileBadge,
|
||||
} = this.props;
|
||||
if (item.fileExst) {
|
||||
markAsRead([], [item.id])
|
||||
.then(() => {
|
||||
updateRootBadge(selectedFolderPathParts[0], 1);
|
||||
updateFileBadge(item.id);
|
||||
})
|
||||
.catch((err) => toastr.error(err));
|
||||
} else {
|
||||
setNewFilesPanelVisible(true);
|
||||
const newFolderIds = selectedFolderPathParts;
|
||||
newFolderIds.push(item.id);
|
||||
setNewFilesIds(newFolderIds);
|
||||
}
|
||||
};
|
||||
|
||||
setConvertDialogVisible = () =>
|
||||
this.setState({ showConvertDialog: !this.state.showConvertDialog });
|
||||
|
||||
onConvert = () => {
|
||||
const { item, t, setSecondaryProgressBarData } = this.props;
|
||||
setSecondaryProgressBarData({
|
||||
icon: "file",
|
||||
visible: true,
|
||||
percent: 0,
|
||||
label: t("Convert"),
|
||||
alert: false,
|
||||
});
|
||||
this.setState({ showConvertDialog: false }, () =>
|
||||
convertFile(item.id).then((convertRes) => {
|
||||
if (convertRes && convertRes[0] && convertRes[0].progress !== 100) {
|
||||
this.getConvertProgress(item.id);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
getConvertProgress = (fileId) => {
|
||||
const {
|
||||
selectedFolderId,
|
||||
filter,
|
||||
setIsLoading,
|
||||
setSecondaryProgressBarData,
|
||||
t,
|
||||
clearSecondaryProgressData,
|
||||
fetchFiles,
|
||||
} = this.props;
|
||||
getFileConversationProgress(fileId).then((res) => {
|
||||
if (res && res[0] && res[0].progress !== 100) {
|
||||
setSecondaryProgressBarData({
|
||||
icon: "file",
|
||||
visible: true,
|
||||
percent: res[0].progress,
|
||||
label: t("Convert"),
|
||||
alert: false,
|
||||
});
|
||||
setTimeout(() => this.getConvertProgress(fileId), 1000);
|
||||
} else {
|
||||
if (res[0].error) {
|
||||
setSecondaryProgressBarData({
|
||||
visible: true,
|
||||
alert: true,
|
||||
});
|
||||
toastr.error(res[0].error);
|
||||
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
|
||||
} else {
|
||||
setSecondaryProgressBarData({
|
||||
icon: "file",
|
||||
visible: true,
|
||||
percent: 100,
|
||||
label: t("Convert"),
|
||||
alert: false,
|
||||
});
|
||||
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
|
||||
const newFilter = filter.clone();
|
||||
fetchFiles(selectedFolderId, newFilter)
|
||||
.catch((err) => {
|
||||
setSecondaryProgressBarData({
|
||||
visible: true,
|
||||
alert: true,
|
||||
});
|
||||
//toastr.error(err);
|
||||
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const { showConvertDialog } = this.state;
|
||||
const {
|
||||
item,
|
||||
canWebEdit,
|
||||
isTrashFolder,
|
||||
canConvert,
|
||||
onFilesClick, // from withFileAction HOC
|
||||
} = this.props;
|
||||
const { fileStatus, access } = item;
|
||||
|
||||
const newItems = item.new || fileStatus === 2;
|
||||
const showNew = !!newItems;
|
||||
|
||||
const accessToEdit =
|
||||
access === ShareAccessRights.FullAccess ||
|
||||
access === ShareAccessRights.None; // TODO: fix access type for owner (now - None)
|
||||
|
||||
const badgesComponent = (
|
||||
<Badges
|
||||
item={item}
|
||||
showNew={showNew}
|
||||
newItems={newItems}
|
||||
canWebEdit={canWebEdit}
|
||||
canConvert={canConvert}
|
||||
isTrashFolder={isTrashFolder}
|
||||
accessToEdit={accessToEdit}
|
||||
onClickLock={this.onClickLock}
|
||||
onClickFavorite={this.onClickFavorite}
|
||||
onShowVersionHistory={this.onShowVersionHistory}
|
||||
onBadgeClick={this.onBadgeClick}
|
||||
setConvertDialogVisible={this.setConvertDialogVisible}
|
||||
onFilesClick={onFilesClick}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showConvertDialog && (
|
||||
<ConvertDialog
|
||||
visible={showConvertDialog}
|
||||
onClose={this.setConvertDialogVisible}
|
||||
onConvert={this.onConvert}
|
||||
/>
|
||||
)}
|
||||
<WrappedComponent badgesComponent={badgesComponent} {...this.props} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return inject(
|
||||
(
|
||||
{
|
||||
auth,
|
||||
formatsStore,
|
||||
treeFoldersStore,
|
||||
filesActionsStore,
|
||||
versionHistoryStore,
|
||||
selectedFolderStore,
|
||||
dialogsStore,
|
||||
filesStore,
|
||||
uploadDataStore,
|
||||
},
|
||||
{ item }
|
||||
) => {
|
||||
const { docserviceStore } = formatsStore;
|
||||
const { isRecycleBinFolder, updateRootBadge } = treeFoldersStore;
|
||||
const {
|
||||
lockFileAction,
|
||||
setFavoriteAction,
|
||||
markAsRead,
|
||||
} = filesActionsStore;
|
||||
const { isTabletView } = auth.settingsStore;
|
||||
const { setIsVerHistoryPanel, fetchFileVersions } = versionHistoryStore;
|
||||
const { setNewFilesPanelVisible, setNewFilesIds } = dialogsStore;
|
||||
const { updateFileBadge, filter, setIsLoading, fetchFiles } = filesStore;
|
||||
const { secondaryProgressDataStore } = uploadDataStore;
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = secondaryProgressDataStore;
|
||||
|
||||
const canWebEdit = docserviceStore.canWebEdit(item.fileExst);
|
||||
const canConvert = docserviceStore.canConvert(item.fileExst);
|
||||
|
||||
return {
|
||||
canWebEdit,
|
||||
canConvert,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
lockFileAction,
|
||||
setFavoriteAction,
|
||||
homepage: config.homepage,
|
||||
isTabletView,
|
||||
setIsVerHistoryPanel,
|
||||
fetchFileVersions,
|
||||
selectedFolderPathParts: selectedFolderStore.pathParts,
|
||||
markAsRead,
|
||||
setNewFilesPanelVisible,
|
||||
setNewFilesIds,
|
||||
updateRootBadge,
|
||||
updateFileBadge,
|
||||
setSecondaryProgressBarData,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
filter,
|
||||
setIsLoading,
|
||||
clearSecondaryProgressData,
|
||||
fetchFiles,
|
||||
};
|
||||
}
|
||||
)(observer(WithBadges));
|
||||
}
|
364
products/ASC.Files/Client/src/HOCs/withContent.js
Normal file
364
products/ASC.Files/Client/src/HOCs/withContent.js
Normal file
@ -0,0 +1,364 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { Trans } from "react-i18next";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import toastr from "studio/toastr";
|
||||
import {
|
||||
AppServerConfig,
|
||||
FileAction,
|
||||
ShareAccessRights,
|
||||
} from "@appserver/common/constants";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
|
||||
import config from "../../package.json";
|
||||
import EditingWrapperComponent from "../components/EditingWrapperComponent";
|
||||
import { getTitleWithoutExst } from "../helpers/files-helpers";
|
||||
|
||||
export default function withContent(WrappedContent) {
|
||||
class WithContent extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let titleWithoutExt = getTitleWithoutExst(props.item);
|
||||
|
||||
if (props.fileActionId === -1) {
|
||||
titleWithoutExt = this.getDefaultName(props.fileActionExt);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
itemTitle: titleWithoutExt,
|
||||
|
||||
//loading: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { fileActionId, fileActionExt } = this.props;
|
||||
if (fileActionId === -1 && fileActionExt !== prevProps.fileActionExt) {
|
||||
const itemTitle = this.getDefaultName(fileActionExt);
|
||||
this.setState({ itemTitle });
|
||||
}
|
||||
// if (fileAction) {
|
||||
// if (fileActionId !== prevProps.fileActionId) {
|
||||
// this.setState({ editingId: fileActionId });
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
getDefaultName = (format) => {
|
||||
const { t } = this.props;
|
||||
|
||||
switch (format) {
|
||||
case "docx":
|
||||
return t("NewDocument");
|
||||
case "xlsx":
|
||||
return t("NewSpreadsheet");
|
||||
case "pptx":
|
||||
return t("NewPresentation");
|
||||
default:
|
||||
return t("NewFolder");
|
||||
}
|
||||
};
|
||||
|
||||
completeAction = (id) => {
|
||||
const { editCompleteAction, item } = this.props;
|
||||
|
||||
const isCancel =
|
||||
(id.currentTarget && id.currentTarget.dataset.action === "cancel") ||
|
||||
id.keyCode === 27;
|
||||
editCompleteAction(id, item, isCancel);
|
||||
};
|
||||
|
||||
updateItem = () => {
|
||||
const {
|
||||
t,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
item,
|
||||
setIsLoading,
|
||||
fileActionId,
|
||||
editCompleteAction,
|
||||
} = this.props;
|
||||
|
||||
const { itemTitle } = this.state;
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
|
||||
setIsLoading(true);
|
||||
const isSameTitle =
|
||||
originalTitle.trim() === itemTitle.trim() || itemTitle.trim() === "";
|
||||
if (isSameTitle) {
|
||||
this.setState({
|
||||
itemTitle: originalTitle,
|
||||
});
|
||||
return editCompleteAction(fileActionId, item, isSameTitle);
|
||||
}
|
||||
|
||||
item.fileExst || item.contentLength
|
||||
? updateFile(fileActionId, itemTitle)
|
||||
.then(() => this.completeAction(fileActionId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FileRenamed", {
|
||||
oldTitle: item.title,
|
||||
newTitle: itemTitle + item.fileExst,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => setIsLoading(false))
|
||||
: renameFolder(fileActionId, itemTitle)
|
||||
.then(() => this.completeAction(fileActionId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FolderRenamed", {
|
||||
folderTitle: item.title,
|
||||
newFoldedTitle: itemTitle,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
cancelUpdateItem = (e) => {
|
||||
const { item } = this.props;
|
||||
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
this.setState({
|
||||
itemTitle: originalTitle,
|
||||
});
|
||||
|
||||
return this.completeAction(e);
|
||||
};
|
||||
|
||||
onClickUpdateItem = (e) => {
|
||||
const { fileActionType } = this.props;
|
||||
|
||||
fileActionType === FileAction.Create
|
||||
? this.createItem(e)
|
||||
: this.updateItem(e);
|
||||
};
|
||||
|
||||
createItem = (e) => {
|
||||
const {
|
||||
createFile,
|
||||
item,
|
||||
setIsLoading,
|
||||
openDocEditor,
|
||||
isPrivacy,
|
||||
isDesktop,
|
||||
replaceFileStream,
|
||||
t,
|
||||
setEncryptionAccess,
|
||||
createFolder,
|
||||
} = this.props;
|
||||
const { itemTitle } = this.state;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const itemId = e.currentTarget.dataset.itemid;
|
||||
|
||||
if (itemTitle.trim() === "") {
|
||||
toastr.warning(t("CreateWithEmptyTitle"));
|
||||
return this.completeAction(itemId);
|
||||
}
|
||||
|
||||
let tab =
|
||||
!isDesktop && item.fileExst
|
||||
? window.open(
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
config.homepage,
|
||||
"/products/files/doceditor"
|
||||
),
|
||||
"_blank"
|
||||
)
|
||||
: null;
|
||||
|
||||
!item.fileExst && !item.contentLength
|
||||
? createFolder(item.parentId, itemTitle)
|
||||
.then(() => this.completeAction(itemId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
<Trans t={t} i18nKey="FolderCreated" ns="Home">
|
||||
New folder {{ itemTitle }} is created
|
||||
</Trans>
|
||||
)
|
||||
)
|
||||
.catch((e) => toastr.error(e))
|
||||
.finally(() => {
|
||||
return setIsLoading(false);
|
||||
})
|
||||
: createFile(item.parentId, `${itemTitle}.${item.fileExst}`)
|
||||
.then((file) => {
|
||||
if (isPrivacy) {
|
||||
return setEncryptionAccess(file).then((encryptedFile) => {
|
||||
if (!encryptedFile) return Promise.resolve();
|
||||
toastr.info(t("EncryptedFileSaving"));
|
||||
return replaceFileStream(
|
||||
file.id,
|
||||
encryptedFile,
|
||||
true,
|
||||
false
|
||||
).then(() =>
|
||||
openDocEditor(file.id, file.providerKey, tab, file.webUrl)
|
||||
);
|
||||
});
|
||||
}
|
||||
return openDocEditor(file.id, file.providerKey, tab, file.webUrl);
|
||||
})
|
||||
.then(() => this.completeAction(itemId))
|
||||
.then(() => {
|
||||
const exst = item.fileExst;
|
||||
return toastr.success(
|
||||
<Trans i18nKey="FileCreated" ns="Home">
|
||||
New file {{ itemTitle }}.{{ exst }} is created
|
||||
</Trans>
|
||||
);
|
||||
})
|
||||
.catch((e) => toastr.error(e))
|
||||
.finally(() => {
|
||||
return setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
renameTitle = (e) => {
|
||||
const { t } = this.props;
|
||||
|
||||
let title = e.target.value;
|
||||
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
|
||||
const regexp = new RegExp('[*+:"<>?|\\\\/]', "gim");
|
||||
if (title.match(regexp)) {
|
||||
toastr.warning(t("ContainsSpecCharacter"));
|
||||
}
|
||||
title = title.replace(regexp, "_");
|
||||
return this.setState({ itemTitle: title });
|
||||
};
|
||||
|
||||
getStatusByDate = () => {
|
||||
const { culture, t, item, sectionWidth } = this.props;
|
||||
const { created, updated, version, fileExst } = item;
|
||||
|
||||
const title =
|
||||
version > 1
|
||||
? t("TitleModified")
|
||||
: fileExst
|
||||
? t("TitleUploaded")
|
||||
: t("TitleCreated");
|
||||
|
||||
const date = fileExst ? updated : created;
|
||||
const dateLabel = new Date(date).toLocaleString(culture);
|
||||
const mobile = (sectionWidth && sectionWidth <= 375) || isMobile;
|
||||
|
||||
return mobile ? dateLabel : `${title}: ${dateLabel}`;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { itemTitle } = this.state;
|
||||
const {
|
||||
item,
|
||||
fileActionId,
|
||||
fileActionExt,
|
||||
isLoading,
|
||||
viewer,
|
||||
t,
|
||||
isTrashFolder,
|
||||
onFilesClick,
|
||||
} = this.props;
|
||||
const { id, fileExst, updated, createdBy, access, fileStatus } = item;
|
||||
|
||||
const titleWithoutExt = getTitleWithoutExst(item);
|
||||
|
||||
const isEdit = id === fileActionId && fileExst === fileActionExt;
|
||||
|
||||
const updatedDate = updated && this.getStatusByDate();
|
||||
|
||||
const fileOwner =
|
||||
createdBy &&
|
||||
((viewer.id === createdBy.id && t("AuthorMe")) ||
|
||||
createdBy.displayName);
|
||||
|
||||
const accessToEdit =
|
||||
access === ShareAccessRights.FullAccess || // only badges?
|
||||
access === ShareAccessRights.None; // TODO: fix access type for owner (now - None)
|
||||
|
||||
const linkStyles = isTrashFolder //|| window.innerWidth <= 1024
|
||||
? { noHover: true }
|
||||
: { onClick: onFilesClick };
|
||||
|
||||
const newItems = item.new || fileStatus === 2;
|
||||
const showNew = !!newItems;
|
||||
|
||||
return isEdit ? (
|
||||
<EditingWrapperComponent
|
||||
itemTitle={itemTitle}
|
||||
itemId={id}
|
||||
isLoading={isLoading}
|
||||
renameTitle={this.renameTitle}
|
||||
onClickUpdateItem={this.onClickUpdateItem}
|
||||
cancelUpdateItem={this.cancelUpdateItem}
|
||||
/>
|
||||
) : (
|
||||
<WrappedContent
|
||||
titleWithoutExt={titleWithoutExt}
|
||||
updatedDate={updatedDate}
|
||||
fileOwner={fileOwner}
|
||||
accessToEdit={accessToEdit}
|
||||
linkStyles={linkStyles}
|
||||
newItems={newItems}
|
||||
showNew={showNew}
|
||||
isTrashFolder={isTrashFolder}
|
||||
onFilesClick={this.onFilesClick}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return inject(
|
||||
({ filesActionsStore, filesStore, treeFoldersStore, auth }, {}) => {
|
||||
const { editCompleteAction } = filesActionsStore;
|
||||
const {
|
||||
setIsLoading,
|
||||
openDocEditor,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
createFile,
|
||||
createFolder,
|
||||
isLoading,
|
||||
} = filesStore;
|
||||
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
|
||||
|
||||
const {
|
||||
type: fileActionType,
|
||||
extension: fileActionExt,
|
||||
id: fileActionId,
|
||||
} = filesStore.fileActionStore;
|
||||
const { replaceFileStream, setEncryptionAccess } = auth;
|
||||
const { culture, isDesktopClient } = auth.settingsStore;
|
||||
|
||||
return {
|
||||
editCompleteAction,
|
||||
setIsLoading,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
openDocEditor,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
fileActionId,
|
||||
editCompleteAction,
|
||||
fileActionType,
|
||||
createFile,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
isDesktop: isDesktopClient,
|
||||
replaceFileStream,
|
||||
setEncryptionAccess,
|
||||
createFolder,
|
||||
fileActionExt,
|
||||
isLoading,
|
||||
culture,
|
||||
homepage: config.homepage,
|
||||
viewer: auth.userStore.user,
|
||||
};
|
||||
}
|
||||
)(observer(WithContent));
|
||||
}
|
503
products/ASC.Files/Client/src/HOCs/withContextOptions.js
Normal file
503
products/ASC.Files/Client/src/HOCs/withContextOptions.js
Normal file
@ -0,0 +1,503 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import copy from "copy-to-clipboard";
|
||||
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { FileAction, AppServerConfig } from "@appserver/common/constants";
|
||||
import toastr from "studio/toastr";
|
||||
|
||||
import config from "../../package.json";
|
||||
|
||||
export default function withContextOptions(WrappedComponent) {
|
||||
class WithContextOptions extends React.Component {
|
||||
onOpenLocation = () => {
|
||||
const { item, openLocationAction } = this.props;
|
||||
const { id, folderId, fileExst } = item;
|
||||
|
||||
const locationId = !fileExst ? id : folderId;
|
||||
openLocationAction(locationId, !fileExst);
|
||||
};
|
||||
|
||||
onOwnerChange = () => {
|
||||
const { setChangeOwnerPanelVisible } = this.props;
|
||||
setChangeOwnerPanelVisible(true);
|
||||
};
|
||||
onMoveAction = () => {
|
||||
const { setMoveToPanelVisible } = this.props;
|
||||
setMoveToPanelVisible(true);
|
||||
};
|
||||
onCopyAction = () => {
|
||||
const { setCopyPanelVisible } = this.props;
|
||||
setCopyPanelVisible(true);
|
||||
};
|
||||
|
||||
showVersionHistory = () => {
|
||||
const {
|
||||
item,
|
||||
isTabletView,
|
||||
fetchFileVersions,
|
||||
setIsVerHistoryPanel,
|
||||
history,
|
||||
homepage,
|
||||
isTrashFolder,
|
||||
} = this.props;
|
||||
const { id } = item;
|
||||
if (isTrashFolder) return;
|
||||
|
||||
if (!isTabletView) {
|
||||
fetchFileVersions(id + "");
|
||||
setIsVerHistoryPanel(true);
|
||||
} else {
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, homepage, `/${id}/history`)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
finalizeVersion = () => {
|
||||
const { item, finalizeVersionAction } = this.props;
|
||||
const { id } = item;
|
||||
finalizeVersionAction(id).catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
onClickFavorite = (e) => {
|
||||
const { item, setFavoriteAction, t } = this.props;
|
||||
const { id } = item;
|
||||
const data = (e.currentTarget && e.currentTarget.dataset) || e;
|
||||
const { action } = data;
|
||||
|
||||
setFavoriteAction(action, id)
|
||||
.then(() =>
|
||||
action === "mark"
|
||||
? toastr.success(t("MarkedAsFavorite"))
|
||||
: toastr.success(t("RemovedFromFavorites"))
|
||||
)
|
||||
.catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
lockFile = () => {
|
||||
const { item, lockFileAction } = this.props;
|
||||
const { id, locked } = item;
|
||||
lockFileAction(id, !locked).catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
onClickLinkForPortal = () => {
|
||||
const { item, homepage, t } = this.props;
|
||||
const { fileExst, canOpenPlayer, webUrl } = item;
|
||||
|
||||
const isFile = !!fileExst;
|
||||
copy(
|
||||
isFile
|
||||
? canOpenPlayer
|
||||
? `${window.location.href}&preview=${id}`
|
||||
: webUrl
|
||||
: `${window.location.origin + homepage}/filter?folder=${id}`
|
||||
);
|
||||
|
||||
toastr.success(t("LinkCopySuccess"));
|
||||
};
|
||||
|
||||
onClickLinkEdit = () => {
|
||||
const { item, openDocEditor } = this.props;
|
||||
const { id, providerKey } = item;
|
||||
openDocEditor(id, providerKey);
|
||||
};
|
||||
|
||||
onClickDownload = () => {
|
||||
const { item, downloadAction, t } = this.props;
|
||||
const { fileExst, contentLength, viewUrl } = item;
|
||||
const isFile = !!fileExst && contentLength;
|
||||
isFile
|
||||
? window.open(viewUrl, "_blank")
|
||||
: downloadAction(t("ArchivingData")).catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
onClickDownloadAs = () => {
|
||||
const { setDownloadDialogVisible } = this.props;
|
||||
setDownloadDialogVisible(true);
|
||||
};
|
||||
|
||||
onDuplicate = () => {
|
||||
const { duplicateAction, t, item } = this.props;
|
||||
duplicateAction(item, t("CopyOperation")).catch((err) =>
|
||||
toastr.error(err)
|
||||
);
|
||||
};
|
||||
|
||||
onClickRename = () => {
|
||||
const { item, setAction } = this.props;
|
||||
const { id, fileExst } = item;
|
||||
setAction({
|
||||
type: FileAction.Rename,
|
||||
extension: fileExst,
|
||||
id,
|
||||
});
|
||||
};
|
||||
|
||||
onChangeThirdPartyInfo = () => {
|
||||
const { item, setThirdpartyInfo } = this.props;
|
||||
const { providerKey } = item;
|
||||
setThirdpartyInfo(providerKey);
|
||||
};
|
||||
|
||||
onMediaFileClick = (fileId) => {
|
||||
const { item, setMediaViewerData } = this.props;
|
||||
const itemId = typeof fileId !== "object" ? fileId : item.id;
|
||||
setMediaViewerData({ visible: true, id: itemId });
|
||||
};
|
||||
|
||||
onClickDelete = () => {
|
||||
const {
|
||||
item,
|
||||
setRemoveItem,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
confirmDelete,
|
||||
setDeleteDialogVisible,
|
||||
t,
|
||||
deleteFileAction,
|
||||
deleteFolderAction,
|
||||
isThirdPartyFolder,
|
||||
} = this.props;
|
||||
const { id, title, fileExst, contentLength, folderId, parentId } = item;
|
||||
|
||||
if (isThirdPartyFolder) {
|
||||
const splitItem = id.split("-");
|
||||
setRemoveItem({ id: splitItem[splitItem.length - 1], title });
|
||||
setDeleteThirdPartyDialogVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirmDelete) {
|
||||
setDeleteDialogVisible(true);
|
||||
} else {
|
||||
const translations = {
|
||||
deleteOperation: t("DeleteOperation"),
|
||||
};
|
||||
|
||||
fileExst || contentLength
|
||||
? deleteFileAction(id, folderId, translations)
|
||||
.then(() => toastr.success(t("FileRemoved")))
|
||||
.catch((err) => toastr.error(err))
|
||||
: deleteFolderAction(id, parentId, translations)
|
||||
.then(() => toastr.success(t("FolderRemoved")))
|
||||
.catch((err) => toastr.error(err));
|
||||
}
|
||||
};
|
||||
|
||||
onClickShare = () => {
|
||||
const { onSelectItem, setSharingPanelVisible, item } = this.props;
|
||||
onSelectItem(item);
|
||||
setSharingPanelVisible(true);
|
||||
};
|
||||
|
||||
getFilesContextOptions = () => {
|
||||
const { item, t, isThirdPartyFolder } = this.props;
|
||||
const { access, contextOptions } = item;
|
||||
const isSharable = access !== 1 && access !== 0;
|
||||
return contextOptions.map((option) => {
|
||||
switch (option) {
|
||||
case "open":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Open"),
|
||||
icon: "images/catalog.folder.react.svg",
|
||||
onClick: this.onOpenLocation,
|
||||
disabled: false,
|
||||
};
|
||||
case "show-version-history":
|
||||
return {
|
||||
key: option,
|
||||
label: t("ShowVersionHistory"),
|
||||
icon: "images/history.react.svg",
|
||||
onClick: this.showVersionHistory,
|
||||
disabled: false,
|
||||
};
|
||||
case "finalize-version":
|
||||
return {
|
||||
key: option,
|
||||
label: t("FinalizeVersion"),
|
||||
icon: "images/history-finalized.react.svg",
|
||||
onClick: this.finalizeVersion,
|
||||
disabled: false,
|
||||
};
|
||||
case "separator0":
|
||||
case "separator1":
|
||||
case "separator2":
|
||||
case "separator3":
|
||||
return { key: option, isSeparator: true };
|
||||
case "open-location":
|
||||
return {
|
||||
key: option,
|
||||
label: t("OpenLocation"),
|
||||
icon: "images/download-as.react.svg",
|
||||
onClick: this.onOpenLocation,
|
||||
disabled: false,
|
||||
};
|
||||
case "mark-as-favorite":
|
||||
return {
|
||||
key: option,
|
||||
label: t("MarkAsFavorite"),
|
||||
icon: "images/favorites.react.svg",
|
||||
onClick: this.onClickFavorite,
|
||||
disabled: false,
|
||||
"data-action": "mark",
|
||||
action: "mark",
|
||||
};
|
||||
case "block-unblock-version":
|
||||
return {
|
||||
key: option,
|
||||
label: t("UnblockVersion"),
|
||||
icon: "images/lock.react.svg",
|
||||
onClick: this.lockFile,
|
||||
disabled: false,
|
||||
};
|
||||
case "sharing-settings":
|
||||
return {
|
||||
key: option,
|
||||
label: t("SharingSettings"),
|
||||
icon: "images/catalog.shared.react.svg",
|
||||
onClick: this.onClickShare,
|
||||
disabled: isSharable,
|
||||
};
|
||||
case "send-by-email":
|
||||
return {
|
||||
key: option,
|
||||
label: t("SendByEmail"),
|
||||
icon: "/static/images/mail.react.svg",
|
||||
disabled: true,
|
||||
};
|
||||
case "owner-change":
|
||||
return {
|
||||
key: option,
|
||||
label: t("ChangeOwner"),
|
||||
icon: "images/catalog.user.react.svg",
|
||||
onClick: this.onOwnerChange,
|
||||
disabled: false,
|
||||
};
|
||||
case "link-for-portal-users":
|
||||
return {
|
||||
key: option,
|
||||
label: t("LinkForPortalUsers"),
|
||||
icon: "/static/images/invitation.link.react.svg",
|
||||
onClick: this.onClickLinkForPortal,
|
||||
disabled: false,
|
||||
};
|
||||
case "edit":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Edit"),
|
||||
icon: "/static/images/access.edit.react.svg",
|
||||
onClick: this.onClickLinkEdit,
|
||||
disabled: false,
|
||||
};
|
||||
case "preview":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Preview"),
|
||||
icon: "EyeIcon",
|
||||
onClick: this.onClickLinkEdit,
|
||||
disabled: true,
|
||||
};
|
||||
case "view":
|
||||
return {
|
||||
key: option,
|
||||
label: t("View"),
|
||||
icon: "/static/images/eye.react.svg",
|
||||
onClick: this.onMediaFileClick,
|
||||
disabled: false,
|
||||
};
|
||||
case "download":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Download"),
|
||||
icon: "images/download.react.svg",
|
||||
onClick: this.onClickDownload,
|
||||
disabled: false,
|
||||
};
|
||||
case "download-as":
|
||||
return {
|
||||
key: option,
|
||||
label: t("DownloadAs"),
|
||||
icon: "images/download-as.react.svg",
|
||||
onClick: this.onClickDownloadAs,
|
||||
disabled: false,
|
||||
};
|
||||
case "move-to":
|
||||
return {
|
||||
key: option,
|
||||
label: t("MoveTo"),
|
||||
icon: "images/move.react.svg",
|
||||
onClick: this.onMoveAction,
|
||||
disabled: false,
|
||||
};
|
||||
case "restore":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Restore"),
|
||||
icon: "images/move.react.svg",
|
||||
onClick: this.onMoveAction,
|
||||
disabled: false,
|
||||
};
|
||||
case "copy-to":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Copy"),
|
||||
icon: "/static/images/copy.react.svg",
|
||||
onClick: this.onCopyAction,
|
||||
disabled: false,
|
||||
};
|
||||
case "copy":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Duplicate"),
|
||||
icon: "/static/images/copy.react.svg",
|
||||
onClick: this.onDuplicate,
|
||||
disabled: false,
|
||||
};
|
||||
case "rename":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Rename"),
|
||||
icon: "images/rename.react.svg",
|
||||
onClick: this.onClickRename,
|
||||
disabled: false,
|
||||
};
|
||||
case "change-thirdparty-info":
|
||||
return {
|
||||
key: option,
|
||||
label: t("ThirdPartyInfo"),
|
||||
icon: "/static/images/access.edit.react.svg",
|
||||
onClick: this.onChangeThirdPartyInfo,
|
||||
disabled: false,
|
||||
};
|
||||
case "delete":
|
||||
return {
|
||||
key: option,
|
||||
label: isThirdPartyFolder ? t("DeleteThirdParty") : t("Delete"),
|
||||
icon: "/static/images/catalog.trash.react.svg",
|
||||
onClick: this.onClickDelete,
|
||||
disabled: false,
|
||||
};
|
||||
case "remove-from-favorites":
|
||||
return {
|
||||
key: option,
|
||||
label: t("RemoveFromFavorites"),
|
||||
icon: "images/favorites.react.svg",
|
||||
onClick: this.onClickFavorite,
|
||||
disabled: false,
|
||||
"data-action": "remove",
|
||||
action: "remove",
|
||||
};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const { actionType, actionId, actionExtension, item } = this.props;
|
||||
const { id, fileExst, contextOptions } = item;
|
||||
|
||||
const isEdit =
|
||||
!!actionType && actionId === id && fileExst === actionExtension;
|
||||
|
||||
const contextOptionsProps =
|
||||
!isEdit && contextOptions && contextOptions.length > 0
|
||||
? {
|
||||
contextOptions: this.getFilesContextOptions(),
|
||||
}
|
||||
: {};
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
contextOptionsProps={contextOptionsProps}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return inject(
|
||||
(
|
||||
{
|
||||
filesStore,
|
||||
filesActionsStore,
|
||||
auth,
|
||||
versionHistoryStore,
|
||||
mediaViewerDataStore,
|
||||
settingsStore,
|
||||
selectedFolderStore,
|
||||
dialogsStore,
|
||||
treeFoldersStore,
|
||||
},
|
||||
{ item }
|
||||
) => {
|
||||
const { openDocEditor, fileActionStore } = filesStore;
|
||||
const {
|
||||
openLocationAction,
|
||||
finalizeVersionAction,
|
||||
setFavoriteAction,
|
||||
lockFileAction,
|
||||
downloadAction,
|
||||
duplicateAction,
|
||||
setThirdpartyInfo,
|
||||
deleteFileAction,
|
||||
deleteFolderAction,
|
||||
onSelectItem,
|
||||
} = filesActionsStore;
|
||||
const {
|
||||
setChangeOwnerPanelVisible,
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
setDownloadDialogVisible,
|
||||
setRemoveItem,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
setDeleteDialogVisible,
|
||||
setSharingPanelVisible,
|
||||
} = dialogsStore;
|
||||
const { isTabletView } = auth.settingsStore;
|
||||
const { setIsVerHistoryPanel, fetchFileVersions } = versionHistoryStore;
|
||||
const { setAction, type, extension, id } = fileActionStore;
|
||||
const { setMediaViewerData } = mediaViewerDataStore;
|
||||
const { isRootFolder } = selectedFolderStore;
|
||||
const { isRecycleBinFolder } = treeFoldersStore;
|
||||
|
||||
const isThirdPartyFolder = item.providerKey && isRootFolder;
|
||||
|
||||
return {
|
||||
openLocationAction,
|
||||
setChangeOwnerPanelVisible,
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
isTabletView,
|
||||
setIsVerHistoryPanel,
|
||||
fetchFileVersions,
|
||||
homepage: config.homepage,
|
||||
finalizeVersionAction,
|
||||
setFavoriteAction,
|
||||
lockFileAction,
|
||||
openDocEditor,
|
||||
downloadAction,
|
||||
setDownloadDialogVisible,
|
||||
duplicateAction,
|
||||
setAction,
|
||||
setThirdpartyInfo,
|
||||
setMediaViewerData,
|
||||
setRemoveItem,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
confirmDelete: settingsStore.confirmDelete,
|
||||
setDeleteDialogVisible,
|
||||
deleteFileAction,
|
||||
deleteFolderAction,
|
||||
isThirdPartyFolder,
|
||||
onSelectItem,
|
||||
setSharingPanelVisible,
|
||||
actionType: type,
|
||||
actionId: id,
|
||||
actionExtension: extension,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
};
|
||||
}
|
||||
)(observer(WithContextOptions));
|
||||
}
|
339
products/ASC.Files/Client/src/HOCs/withFileActions.js
Normal file
339
products/ASC.Files/Client/src/HOCs/withFileActions.js
Normal file
@ -0,0 +1,339 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { ReactSVG } from "react-svg";
|
||||
|
||||
import IconButton from "@appserver/components/icon-button";
|
||||
import Text from "@appserver/components/text";
|
||||
|
||||
import { EncryptedFileIcon } from "../components/Icons";
|
||||
|
||||
const svgLoader = () => <div style={{ width: "24px" }}></div>;
|
||||
export default function withFileActions(WrappedFileItem) {
|
||||
class WithFileActions extends React.Component {
|
||||
onContentRowSelect = (checked, file) => {
|
||||
const { selectRowAction } = this.props;
|
||||
if (!file) return;
|
||||
selectRowAction(checked, file);
|
||||
};
|
||||
|
||||
onClickShare = () => {
|
||||
const { onSelectItem, setSharingPanelVisible, item } = this.props;
|
||||
onSelectItem(item);
|
||||
setSharingPanelVisible(true);
|
||||
};
|
||||
|
||||
rowContextClick = () => {
|
||||
const { onSelectItem, item } = this.props;
|
||||
onSelectItem(item);
|
||||
};
|
||||
|
||||
getSharedButton = (shared) => {
|
||||
const { t } = this.props;
|
||||
const color = shared ? "#657077" : "#a3a9ae";
|
||||
return (
|
||||
<Text
|
||||
className="share-button"
|
||||
as="span"
|
||||
title={t("Share")}
|
||||
fontSize="12px"
|
||||
fontWeight={600}
|
||||
color={color}
|
||||
display="inline-flex"
|
||||
onClick={this.onClickShare}
|
||||
>
|
||||
<IconButton
|
||||
className="share-button-icon"
|
||||
color={color}
|
||||
hoverColor="#657077"
|
||||
size={18}
|
||||
iconName="images/catalog.shared.react.svg"
|
||||
/>
|
||||
{t("Share")}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
getItemIcon = (isEdit) => {
|
||||
const { item, isPrivacy } = this.props;
|
||||
const { icon, fileExst } = item;
|
||||
return (
|
||||
<>
|
||||
<ReactSVG
|
||||
className={`react-svg-icon${isEdit ? " is-edit" : ""}`}
|
||||
src={icon}
|
||||
loading={svgLoader}
|
||||
/>
|
||||
{isPrivacy && fileExst && <EncryptedFileIcon isEdit={isEdit} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
onDropZoneUpload = (files, uploadToFolder) => {
|
||||
const {
|
||||
selectedFolderId,
|
||||
dragging,
|
||||
setDragging,
|
||||
startUpload,
|
||||
} = this.props;
|
||||
|
||||
const folderId = uploadToFolder ? uploadToFolder : selectedFolderId;
|
||||
dragging && setDragging(false);
|
||||
startUpload(files, folderId, t);
|
||||
};
|
||||
|
||||
onDrop = (items) => {
|
||||
const { item, selectedFolderId } = this.props;
|
||||
const { fileExst, id } = item;
|
||||
|
||||
if (!fileExst) {
|
||||
this.onDropZoneUpload(items, id);
|
||||
} else {
|
||||
this.onDropZoneUpload(items, selectedFolderId);
|
||||
}
|
||||
};
|
||||
|
||||
onMouseDown = (e) => {
|
||||
const { draggable, setTooltipPosition, setStartDrag } = this.props;
|
||||
if (!draggable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
window.innerWidth < 1025 ||
|
||||
e.target.tagName === "rect" ||
|
||||
e.target.tagName === "path"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const mouseButton = e.which
|
||||
? e.which !== 1
|
||||
: e.button
|
||||
? e.button !== 0
|
||||
: false;
|
||||
const label = e.currentTarget.getAttribute("label");
|
||||
if (mouseButton || e.currentTarget.tagName !== "DIV" || label) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTooltipPosition(e.pageX, e.pageY);
|
||||
setStartDrag(true);
|
||||
};
|
||||
|
||||
onFilesClick = () => {
|
||||
const {
|
||||
filter,
|
||||
parentFolder,
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
isImage,
|
||||
isSound,
|
||||
isVideo,
|
||||
canWebEdit,
|
||||
item,
|
||||
isTrashFolder,
|
||||
openDocEditor,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
setMediaViewerData,
|
||||
} = this.props;
|
||||
const { id, fileExst, viewUrl, providerKey, contentLength } = item;
|
||||
|
||||
if (isTrashFolder) return;
|
||||
|
||||
if (!fileExst && !contentLength) {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!expandedKeys.includes(parentFolder + "")) {
|
||||
addExpandedKeys(parentFolder + "");
|
||||
}
|
||||
|
||||
fetchFiles(id, filter)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
setIsLoading(false);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
} else {
|
||||
if (canWebEdit) {
|
||||
return openDocEditor(id, providerKey);
|
||||
}
|
||||
|
||||
if (isImage || isSound || isVideo) {
|
||||
setMediaViewerData({ visible: true, id });
|
||||
return;
|
||||
}
|
||||
|
||||
return window.open(viewUrl, "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
item,
|
||||
isRecycleBin,
|
||||
draggable,
|
||||
canShare,
|
||||
isPrivacy,
|
||||
actionType,
|
||||
actionExtension,
|
||||
actionId,
|
||||
sectionWidth,
|
||||
checked,
|
||||
dragging,
|
||||
isFolder,
|
||||
} = this.props;
|
||||
const { fileExst, access, contentLength, id, shared } = item;
|
||||
|
||||
const isEdit =
|
||||
!!actionType && actionId === id && fileExst === actionExtension;
|
||||
|
||||
const isDragging = isFolder && access < 2 && !isRecycleBin;
|
||||
|
||||
let className = isDragging ? " droppable" : "";
|
||||
if (draggable) className += " draggable not-selectable";
|
||||
|
||||
let value = fileExst || contentLength ? `file_${id}` : `folder_${id}`;
|
||||
value += draggable ? "_draggable" : "";
|
||||
|
||||
const isMobile = sectionWidth < 500;
|
||||
const displayShareButton = isMobile
|
||||
? "26px"
|
||||
: !canShare
|
||||
? "38px"
|
||||
: "96px";
|
||||
|
||||
const sharedButton =
|
||||
!canShare || (isPrivacy && !fileExst) || isEdit || id <= 0 || isMobile
|
||||
? null
|
||||
: this.getSharedButton(shared);
|
||||
|
||||
const checkedProps = isEdit || id <= 0 ? {} : { checked };
|
||||
const element = this.getItemIcon(isEdit || id <= 0);
|
||||
|
||||
return (
|
||||
<WrappedFileItem
|
||||
onContentRowSelect={this.onContentRowSelect}
|
||||
onClickShare={this.onClickShare}
|
||||
rowContextClick={this.rowContextClick}
|
||||
onDrop={this.onDrop}
|
||||
onMouseDown={this.onMouseDown}
|
||||
onFilesClick={this.onFilesClick}
|
||||
getClassName={this.getClassName}
|
||||
className={className}
|
||||
isDragging={isDragging}
|
||||
value={value}
|
||||
displayShareButton={displayShareButton}
|
||||
isPrivacy={isPrivacy}
|
||||
sharedButton={sharedButton}
|
||||
checkedProps={checkedProps}
|
||||
element={element}
|
||||
dragging={dragging}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return inject(
|
||||
(
|
||||
{
|
||||
filesActionsStore,
|
||||
dialogsStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
filesStore,
|
||||
uploadDataStore,
|
||||
formatsStore,
|
||||
mediaViewerDataStore,
|
||||
},
|
||||
{ item, t, history }
|
||||
) => {
|
||||
const { selectRowAction, onSelectItem } = filesActionsStore;
|
||||
const { setSharingPanelVisible } = dialogsStore;
|
||||
const {
|
||||
isPrivacyFolder,
|
||||
isRecycleBinFolder,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
} = treeFoldersStore;
|
||||
const { id: selectedFolderId, isRootFolder } = selectedFolderStore;
|
||||
const {
|
||||
dragging,
|
||||
setDragging,
|
||||
selection,
|
||||
setTooltipPosition,
|
||||
setStartDrag,
|
||||
fileActionStore,
|
||||
canShare,
|
||||
isFileSelected,
|
||||
filter,
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
openDocEditor,
|
||||
} = filesStore;
|
||||
const { startUpload } = uploadDataStore;
|
||||
const { type, extension, id } = fileActionStore;
|
||||
const {
|
||||
iconFormatsStore,
|
||||
mediaViewersFormatsStore,
|
||||
docserviceStore,
|
||||
} = formatsStore;
|
||||
const { setMediaViewerData } = mediaViewerDataStore;
|
||||
|
||||
const selectedItem = selection.find(
|
||||
(x) => x.id === item.id && x.fileExst === item.fileExst
|
||||
);
|
||||
|
||||
const draggable =
|
||||
!isRecycleBinFolder && selectedItem && selectedItem.id !== id;
|
||||
|
||||
const isFolder = selectedItem
|
||||
? false
|
||||
: item.fileExst //|| item.contentLength
|
||||
? false
|
||||
: true;
|
||||
|
||||
const isImage = iconFormatsStore.isImage(item.fileExst);
|
||||
const isSound = iconFormatsStore.isSound(item.fileExst);
|
||||
const isVideo = mediaViewersFormatsStore.isVideo(item.fileExst);
|
||||
const canWebEdit = docserviceStore.canWebEdit(item.fileExst);
|
||||
|
||||
return {
|
||||
t,
|
||||
item,
|
||||
selectRowAction,
|
||||
onSelectItem,
|
||||
setSharingPanelVisible,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
selectedFolderId,
|
||||
dragging,
|
||||
setDragging,
|
||||
startUpload,
|
||||
draggable,
|
||||
setTooltipPosition,
|
||||
setStartDrag,
|
||||
history,
|
||||
isFolder,
|
||||
isRootFolder,
|
||||
canShare,
|
||||
actionType: type,
|
||||
actionExtension: extension,
|
||||
actionId: id,
|
||||
checked: isFileSelected(item.id, item.parentId),
|
||||
filter,
|
||||
parentFolder: selectedFolderStore.parentId,
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
isImage,
|
||||
isSound,
|
||||
isVideo,
|
||||
canWebEdit,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
openDocEditor,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
setMediaViewerData,
|
||||
};
|
||||
}
|
||||
)(observer(WithFileActions));
|
||||
}
|
51
products/ASC.Files/Client/src/HOCs/withLoader.js
Normal file
51
products/ASC.Files/Client/src/HOCs/withLoader.js
Normal file
@ -0,0 +1,51 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
|
||||
let loadTimeout = null;
|
||||
export default function withLoader(WrappedComponent, type) {
|
||||
const withLoader = (props) => {
|
||||
const { tReady, firstLoad, isLoaded, isLoading } = props;
|
||||
const [inLoad, setInLoad] = useState(false);
|
||||
|
||||
const cleanTimer = () => {
|
||||
loadTimeout && clearTimeout(loadTimeout);
|
||||
loadTimeout = null;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading) {
|
||||
cleanTimer();
|
||||
loadTimeout = setTimeout(() => {
|
||||
console.log("inLoad", true);
|
||||
setInLoad(true);
|
||||
}, 500);
|
||||
} else {
|
||||
cleanTimer();
|
||||
console.log("inLoad", false);
|
||||
setInLoad(false);
|
||||
}
|
||||
|
||||
return () => {
|
||||
cleanTimer();
|
||||
};
|
||||
}, [isLoading]);
|
||||
|
||||
return firstLoad || !isLoaded || (isMobile && inLoad) || !tReady ? (
|
||||
<Loaders.Rows />
|
||||
) : (
|
||||
<WrappedComponent {...props} />
|
||||
);
|
||||
};
|
||||
|
||||
return inject(({ auth, filesStore }) => {
|
||||
const { firstLoad, isLoading } = filesStore;
|
||||
return {
|
||||
firstLoad,
|
||||
isLoaded: auth.isLoaded,
|
||||
isLoading,
|
||||
};
|
||||
})(observer(withLoader));
|
||||
}
|
123
products/ASC.Files/Client/src/components/Badges.js
Normal file
123
products/ASC.Files/Client/src/components/Badges.js
Normal file
@ -0,0 +1,123 @@
|
||||
import React from "react";
|
||||
import Badge from "@appserver/components/badge";
|
||||
import IconButton from "@appserver/components/icon-button";
|
||||
import {
|
||||
StyledFavoriteIcon,
|
||||
StyledFileActionsConvertEditDocIcon,
|
||||
StyledFileActionsLockedIcon,
|
||||
} from "./Icons";
|
||||
|
||||
const Badges = ({
|
||||
newItems,
|
||||
item,
|
||||
canWebEdit,
|
||||
isTrashFolder,
|
||||
/* canConvert, */
|
||||
accessToEdit,
|
||||
showNew,
|
||||
onFilesClick,
|
||||
onClickLock,
|
||||
onClickFavorite,
|
||||
onShowVersionHistory,
|
||||
onBadgeClick,
|
||||
/*setConvertDialogVisible*/
|
||||
}) => {
|
||||
const { id, locked, fileStatus, versionGroup, title, fileExst } = item;
|
||||
|
||||
return fileExst ? (
|
||||
<div className="badges additional-badges">
|
||||
{/* TODO: Uncomment after fix conversation {canConvert && !isTrashFolder && (
|
||||
<IconButton
|
||||
onClick={setConvertDialogVisible}
|
||||
iconName="FileActionsConvertIcon"
|
||||
className="badge"
|
||||
size="small"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
hoverColor="#3B72A7"
|
||||
/>
|
||||
)} */}
|
||||
{canWebEdit && !isTrashFolder && accessToEdit && (
|
||||
<IconButton
|
||||
onClick={onFilesClick}
|
||||
iconName="/static/images/access.edit.react.svg"
|
||||
className="badge icons-group"
|
||||
size="small"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
hoverColor="#3B72A7"
|
||||
/>
|
||||
)}
|
||||
{locked && (
|
||||
<StyledFileActionsLockedIcon
|
||||
className="badge lock-file icons-group"
|
||||
size="small"
|
||||
data-id={id}
|
||||
data-locked={true}
|
||||
onClick={onClickLock}
|
||||
/>
|
||||
)}
|
||||
{fileStatus === 32 && !isTrashFolder && (
|
||||
<StyledFavoriteIcon
|
||||
className="favorite icons-group"
|
||||
size="small"
|
||||
data-action="remove"
|
||||
data-id={id}
|
||||
data-title={title}
|
||||
onClick={onClickFavorite}
|
||||
/>
|
||||
)}
|
||||
{fileStatus === 1 && (
|
||||
<StyledFileActionsConvertEditDocIcon className="badge" size="small" />
|
||||
)}
|
||||
{versionGroup > 1 && (
|
||||
<Badge
|
||||
className="badge-version icons-group"
|
||||
backgroundColor="#A3A9AE"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={`Ver.${versionGroup}`}
|
||||
maxWidth="50px"
|
||||
onClick={onShowVersionHistory}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)}
|
||||
{showNew && (
|
||||
<Badge
|
||||
className="badge-version icons-group"
|
||||
backgroundColor="#ED7309"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={`New`}
|
||||
maxWidth="50px"
|
||||
onClick={onBadgeClick}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
showNew && (
|
||||
<Badge
|
||||
className="new-items"
|
||||
backgroundColor="#ED7309"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={newItems}
|
||||
maxWidth="50px"
|
||||
onClick={onBadgeClick}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default Badges;
|
@ -2,6 +2,35 @@ import React, { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import Button from "@appserver/components/button";
|
||||
import TextInput from "@appserver/components/text-input";
|
||||
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
|
||||
|
||||
import CheckIcon from "../../public/images/check.react.svg";
|
||||
import CrossIcon from "../../../../../public/images/cross.react.svg";
|
||||
|
||||
const StyledCheckIcon = styled(CheckIcon)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #a3a9ae;
|
||||
}
|
||||
:hover {
|
||||
fill: #657077;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledCrossIcon = styled(CrossIcon)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #a3a9ae;
|
||||
}
|
||||
:hover {
|
||||
fill: #657077;
|
||||
}
|
||||
`;
|
||||
|
||||
export const okIcon = <StyledCheckIcon className="edit-ok-icon" size="scale" />;
|
||||
export const cancelIcon = (
|
||||
<StyledCrossIcon className="edit-cancel-icon" size="scale" />
|
||||
);
|
||||
|
||||
const EditingWrapper = styled.div`
|
||||
width: 100%;
|
||||
@ -49,8 +78,6 @@ const EditingWrapperComponent = (props) => {
|
||||
const {
|
||||
itemTitle,
|
||||
itemId,
|
||||
okIcon,
|
||||
cancelIcon,
|
||||
renameTitle,
|
||||
onClickUpdateItem,
|
||||
cancelUpdateItem,
|
36
products/ASC.Files/Client/src/components/Icons.js
Normal file
36
products/ASC.Files/Client/src/components/Icons.js
Normal file
@ -0,0 +1,36 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
|
||||
|
||||
import FavoriteIcon from "../../public/images/favorite.react.svg";
|
||||
import FileActionsConvertEditDocIcon from "../../public/images/file.actions.convert.edit.doc.react.svg";
|
||||
import FileActionsLockedIcon from "../../public/images/file.actions.locked.react.svg";
|
||||
|
||||
export const EncryptedFileIcon = styled.div`
|
||||
background: url("images/security.svg") no-repeat 0 0 / 16px 16px transparent;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
margin-top: 14px;
|
||||
margin-left: ${(props) => (props.isEdit ? "40px" : "12px")};
|
||||
`;
|
||||
|
||||
export const StyledFavoriteIcon = styled(FavoriteIcon)`
|
||||
${commonIconsStyles}
|
||||
`;
|
||||
|
||||
export const StyledFileActionsConvertEditDocIcon = styled(
|
||||
FileActionsConvertEditDocIcon
|
||||
)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #3b72a7;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledFileActionsLockedIcon = styled(FileActionsLockedIcon)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #3b72a7;
|
||||
}
|
||||
`;
|
@ -1,68 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import RowContainer from "@appserver/components/row-container";
|
||||
import { Consumer } from "@appserver/components/utils/context";
|
||||
import SimpleFilesRow from "./SimpleFilesRow";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
let loadTimeout = null;
|
||||
|
||||
const FilesRowContainer = ({ isLoaded, isLoading, filesList, tReady }) => {
|
||||
const [inLoad, setInLoad] = useState(false);
|
||||
|
||||
const cleanTimer = () => {
|
||||
loadTimeout && clearTimeout(loadTimeout);
|
||||
loadTimeout = null;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading) {
|
||||
cleanTimer();
|
||||
loadTimeout = setTimeout(() => {
|
||||
console.log("inLoad", true);
|
||||
setInLoad(true);
|
||||
}, 500);
|
||||
} else {
|
||||
cleanTimer();
|
||||
console.log("inLoad", false);
|
||||
setInLoad(false);
|
||||
}
|
||||
|
||||
return () => {
|
||||
cleanTimer();
|
||||
};
|
||||
}, [isLoading]);
|
||||
|
||||
return !isLoaded || (isMobile && inLoad) || !tReady ? (
|
||||
<Loaders.Rows />
|
||||
) : (
|
||||
<Consumer>
|
||||
{(context) => (
|
||||
<RowContainer
|
||||
className="files-row-container"
|
||||
draggable
|
||||
useReactWindow={false}
|
||||
>
|
||||
{filesList.map((item, index) => (
|
||||
<SimpleFilesRow
|
||||
key={`${item.id}_${index}`}
|
||||
item={item}
|
||||
sectionWidth={context.sectionWidth}
|
||||
/>
|
||||
))}
|
||||
</RowContainer>
|
||||
)}
|
||||
</Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth, filesStore }) => {
|
||||
const { filesList, isLoading } = filesStore;
|
||||
|
||||
return {
|
||||
filesList,
|
||||
isLoading,
|
||||
isLoaded: auth.isLoaded,
|
||||
};
|
||||
})(observer(FilesRowContainer));
|
@ -1,902 +0,0 @@
|
||||
import React from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import Link from "@appserver/components/link";
|
||||
import Text from "@appserver/components/text";
|
||||
import RowContent from "@appserver/components/row-content";
|
||||
import IconButton from "@appserver/components/icon-button";
|
||||
import Badge from "@appserver/components/badge";
|
||||
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
|
||||
import {
|
||||
convertFile,
|
||||
getFileConversationProgress,
|
||||
} from "@appserver/common/api/files";
|
||||
import {
|
||||
AppServerConfig,
|
||||
FileAction,
|
||||
ShareAccessRights,
|
||||
} from "@appserver/common/constants";
|
||||
import toastr from "studio/toastr";
|
||||
import FavoriteIcon from "../../../../../../../public/images/favorite.react.svg";
|
||||
import FileActionsConvertEditDocIcon from "../../../../../../../public/images/file.actions.convert.edit.doc.react.svg";
|
||||
import FileActionsLockedIcon from "../../../../../../../public/images/file.actions.locked.react.svg";
|
||||
import CheckIcon from "../../../../../../../public/images/check.react.svg";
|
||||
import CrossIcon from "../../../../../../../../../../public/images/cross.react.svg";
|
||||
import { TIMEOUT } from "../../../../../../helpers/constants";
|
||||
import { getTitleWithoutExst } from "../../../../../../helpers/files-helpers";
|
||||
import { ConvertDialog } from "../../../../../dialogs";
|
||||
import EditingWrapperComponent from "../EditingWrapperComponent";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import config from "../../../../../../../package.json";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
|
||||
const sideColor = "#A3A9AE";
|
||||
const StyledCheckIcon = styled(CheckIcon)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #a3a9ae;
|
||||
}
|
||||
:hover {
|
||||
fill: #657077;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledCrossIcon = styled(CrossIcon)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #a3a9ae;
|
||||
}
|
||||
:hover {
|
||||
fill: #657077;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledFavoriteIcon = styled(FavoriteIcon)`
|
||||
${commonIconsStyles}
|
||||
`;
|
||||
|
||||
const StyledFileActionsConvertEditDocIcon = styled(
|
||||
FileActionsConvertEditDocIcon
|
||||
)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #3b72a7;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledFileActionsLockedIcon = styled(FileActionsLockedIcon)`
|
||||
${commonIconsStyles}
|
||||
path {
|
||||
fill: #3b72a7;
|
||||
}
|
||||
`;
|
||||
const SimpleFilesRowContent = styled(RowContent)`
|
||||
.badge-ext {
|
||||
margin-left: -8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.lock-file {
|
||||
cursor: pointer;
|
||||
}
|
||||
.badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.favorite {
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.share-icon {
|
||||
margin-top: -4px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.row_update-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
`;
|
||||
|
||||
const okIcon = <StyledCheckIcon className="edit-ok-icon" size="scale" />;
|
||||
|
||||
const cancelIcon = (
|
||||
<StyledCrossIcon className="edit-cancel-icon" size="scale" />
|
||||
);
|
||||
|
||||
class FilesRowContent extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let titleWithoutExt = getTitleWithoutExst(props.item);
|
||||
|
||||
if (props.fileActionId === -1) {
|
||||
titleWithoutExt = this.getDefaultName(props.fileActionExt);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
itemTitle: titleWithoutExt,
|
||||
showConvertDialog: false,
|
||||
//loading: false
|
||||
};
|
||||
}
|
||||
|
||||
completeAction = (id) => {
|
||||
const isCancel =
|
||||
(id.currentTarget && id.currentTarget.dataset.action === "cancel") ||
|
||||
id.keyCode === 27;
|
||||
this.props.editCompleteAction(id, this.props.item, isCancel);
|
||||
};
|
||||
|
||||
updateItem = () => {
|
||||
const {
|
||||
t,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
item,
|
||||
setIsLoading,
|
||||
fileActionId,
|
||||
editCompleteAction,
|
||||
} = this.props;
|
||||
|
||||
const { itemTitle } = this.state;
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
|
||||
setIsLoading(true);
|
||||
const isSameTitle =
|
||||
originalTitle.trim() === itemTitle.trim() || itemTitle.trim() === "";
|
||||
if (isSameTitle) {
|
||||
this.setState({
|
||||
itemTitle: originalTitle,
|
||||
});
|
||||
return editCompleteAction(fileActionId, item, isSameTitle);
|
||||
}
|
||||
|
||||
item.fileExst || item.contentLength
|
||||
? updateFile(fileActionId, itemTitle)
|
||||
.then(() => this.completeAction(fileActionId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FileRenamed", {
|
||||
oldTitle: item.title,
|
||||
newTitle: itemTitle + item.fileExst,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => setIsLoading(false))
|
||||
: renameFolder(fileActionId, itemTitle)
|
||||
.then(() => this.completeAction(fileActionId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
t("FolderRenamed", {
|
||||
folderTitle: item.title,
|
||||
newFoldedTitle: itemTitle,
|
||||
})
|
||||
)
|
||||
)
|
||||
.catch((err) => toastr.error(err))
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
createItem = (e) => {
|
||||
const {
|
||||
createFile,
|
||||
item,
|
||||
setIsLoading,
|
||||
openDocEditor,
|
||||
isPrivacy,
|
||||
isDesktop,
|
||||
replaceFileStream,
|
||||
t,
|
||||
setEncryptionAccess,
|
||||
createFolder,
|
||||
} = this.props;
|
||||
const { itemTitle } = this.state;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const itemId = e.currentTarget.dataset.itemid;
|
||||
|
||||
if (itemTitle.trim() === "") {
|
||||
toastr.warning(this.props.t("CreateWithEmptyTitle"));
|
||||
return this.completeAction(itemId);
|
||||
}
|
||||
|
||||
let tab =
|
||||
!isDesktop && item.fileExst
|
||||
? window.open(
|
||||
combineUrl(
|
||||
AppServerConfig.proxyURL,
|
||||
config.homepage,
|
||||
"/products/files/doceditor"
|
||||
),
|
||||
"_blank"
|
||||
)
|
||||
: null;
|
||||
|
||||
!item.fileExst && !item.contentLength
|
||||
? createFolder(item.parentId, itemTitle)
|
||||
.then(() => this.completeAction(itemId))
|
||||
.then(() =>
|
||||
toastr.success(
|
||||
<Trans t={t} i18nKey="FolderCreated" ns="Home">
|
||||
New folder {{ itemTitle }} is created
|
||||
</Trans>
|
||||
)
|
||||
)
|
||||
.catch((e) => toastr.error(e))
|
||||
.finally(() => {
|
||||
return setIsLoading(false);
|
||||
})
|
||||
: createFile(item.parentId, `${itemTitle}.${item.fileExst}`)
|
||||
.then((file) => {
|
||||
if (isPrivacy) {
|
||||
return setEncryptionAccess(file).then((encryptedFile) => {
|
||||
if (!encryptedFile) return Promise.resolve();
|
||||
toastr.info(t("EncryptedFileSaving"));
|
||||
return replaceFileStream(
|
||||
file.id,
|
||||
encryptedFile,
|
||||
true,
|
||||
false
|
||||
).then(() =>
|
||||
openDocEditor(file.id, file.providerKey, tab, file.webUrl)
|
||||
);
|
||||
});
|
||||
}
|
||||
return openDocEditor(file.id, file.providerKey, tab, file.webUrl);
|
||||
})
|
||||
.then(() => this.completeAction(itemId))
|
||||
.then(() => {
|
||||
const exst = item.fileExst;
|
||||
return toastr.success(
|
||||
<Trans i18nKey="FileCreated" ns="Home">
|
||||
New file {{ itemTitle }}.{{ exst }} is created
|
||||
</Trans>
|
||||
);
|
||||
})
|
||||
.catch((e) => toastr.error(e))
|
||||
.finally(() => {
|
||||
return setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { fileActionId, fileActionExt } = this.props;
|
||||
if (fileActionId === -1 && fileActionExt !== prevProps.fileActionExt) {
|
||||
const itemTitle = this.getDefaultName(fileActionExt);
|
||||
this.setState({ itemTitle });
|
||||
}
|
||||
// if (fileAction) {
|
||||
// if (fileActionId !== prevProps.fileActionId) {
|
||||
// this.setState({ editingId: fileActionId });
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
renameTitle = (e) => {
|
||||
let title = e.target.value;
|
||||
//const chars = '*+:"<>?|/'; TODO: think how to solve problem with interpolation escape values in i18n translate
|
||||
const regexp = new RegExp('[*+:"<>?|\\\\/]', "gim");
|
||||
if (title.match(regexp)) {
|
||||
toastr.warning(this.props.t("ContainsSpecCharacter"));
|
||||
}
|
||||
title = title.replace(regexp, "_");
|
||||
return this.setState({ itemTitle: title });
|
||||
};
|
||||
|
||||
cancelUpdateItem = (e) => {
|
||||
const originalTitle = getTitleWithoutExst(this.props.item);
|
||||
this.setState({
|
||||
itemTitle: originalTitle,
|
||||
});
|
||||
|
||||
return this.completeAction(e);
|
||||
};
|
||||
|
||||
onClickUpdateItem = (e) => {
|
||||
this.props.fileActionType === FileAction.Create
|
||||
? this.createItem(e)
|
||||
: this.updateItem(e);
|
||||
};
|
||||
|
||||
onFilesClick = () => {
|
||||
const {
|
||||
filter,
|
||||
parentFolder,
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
isImage,
|
||||
isSound,
|
||||
isVideo,
|
||||
canWebEdit,
|
||||
item,
|
||||
isTrashFolder,
|
||||
openDocEditor,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
setMediaViewerData,
|
||||
} = this.props;
|
||||
const { id, fileExst, viewUrl, providerKey, contentLength } = item;
|
||||
|
||||
if (isTrashFolder) return;
|
||||
|
||||
if (!fileExst && !contentLength) {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!expandedKeys.includes(parentFolder + "")) {
|
||||
addExpandedKeys(parentFolder + "");
|
||||
}
|
||||
|
||||
fetchFiles(id, filter)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
setIsLoading(false);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
} else {
|
||||
if (canWebEdit) {
|
||||
return openDocEditor(id, providerKey);
|
||||
}
|
||||
|
||||
if (isImage || isSound || isVideo) {
|
||||
setMediaViewerData({ visible: true, id });
|
||||
return;
|
||||
}
|
||||
|
||||
return window.open(viewUrl, "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
onMobileRowClick = () => {
|
||||
if (this.props.isTrashFolder || window.innerWidth > 1024) return;
|
||||
this.onFilesClick();
|
||||
};
|
||||
|
||||
getStatusByDate = () => {
|
||||
const { culture, t, item, sectionWidth } = this.props;
|
||||
const { created, updated, version, fileExst } = item;
|
||||
|
||||
const title =
|
||||
version > 1
|
||||
? t("TitleModified")
|
||||
: fileExst
|
||||
? t("TitleUploaded")
|
||||
: t("TitleCreated");
|
||||
|
||||
const date = fileExst ? updated : created;
|
||||
const dateLabel = new Date(date).toLocaleString(culture);
|
||||
const mobile = (sectionWidth && sectionWidth <= 375) || isMobile;
|
||||
|
||||
return mobile ? dateLabel : `${title}: ${dateLabel}`;
|
||||
};
|
||||
|
||||
getDefaultName = (format) => {
|
||||
const { t } = this.props;
|
||||
|
||||
switch (format) {
|
||||
case "docx":
|
||||
return t("NewDocument");
|
||||
case "xlsx":
|
||||
return t("NewSpreadsheet");
|
||||
case "pptx":
|
||||
return t("NewPresentation");
|
||||
default:
|
||||
return t("NewFolder");
|
||||
}
|
||||
};
|
||||
|
||||
onShowVersionHistory = () => {
|
||||
const {
|
||||
homepage,
|
||||
isTabletView,
|
||||
item,
|
||||
setIsVerHistoryPanel,
|
||||
fetchFileVersions,
|
||||
history,
|
||||
isTrashFolder,
|
||||
} = this.props;
|
||||
if (isTrashFolder) return;
|
||||
|
||||
if (!isTabletView) {
|
||||
fetchFileVersions(item.id + "");
|
||||
setIsVerHistoryPanel(true);
|
||||
} else {
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, homepage, `/${item.id}/history`)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
onBadgeClick = () => {
|
||||
const {
|
||||
item,
|
||||
selectedFolderPathParts,
|
||||
markAsRead,
|
||||
setNewFilesPanelVisible,
|
||||
setNewFilesIds,
|
||||
updateRootBadge,
|
||||
updateFileBadge,
|
||||
} = this.props;
|
||||
if (item.fileExst) {
|
||||
markAsRead([], [item.id])
|
||||
.then(() => {
|
||||
updateRootBadge(selectedFolderPathParts[0], 1);
|
||||
updateFileBadge(item.id);
|
||||
})
|
||||
.catch((err) => toastr.error(err));
|
||||
} else {
|
||||
setNewFilesPanelVisible(true);
|
||||
const newFolderIds = this.props.selectedFolderPathParts;
|
||||
newFolderIds.push(item.id);
|
||||
setNewFilesIds(newFolderIds);
|
||||
}
|
||||
};
|
||||
|
||||
setConvertDialogVisible = () =>
|
||||
this.setState({ showConvertDialog: !this.state.showConvertDialog });
|
||||
|
||||
getConvertProgress = (fileId) => {
|
||||
const {
|
||||
selectedFolderId,
|
||||
filter,
|
||||
setIsLoading,
|
||||
setSecondaryProgressBarData,
|
||||
t,
|
||||
clearSecondaryProgressData,
|
||||
fetchFiles,
|
||||
} = this.props;
|
||||
getFileConversationProgress(fileId).then((res) => {
|
||||
if (res && res[0] && res[0].progress !== 100) {
|
||||
setSecondaryProgressBarData({
|
||||
icon: "file",
|
||||
visible: true,
|
||||
percent: res[0].progress,
|
||||
label: t("Convert"),
|
||||
alert: false,
|
||||
});
|
||||
setTimeout(() => this.getConvertProgress(fileId), 1000);
|
||||
} else {
|
||||
if (res[0].error) {
|
||||
setSecondaryProgressBarData({
|
||||
visible: true,
|
||||
alert: true,
|
||||
});
|
||||
toastr.error(res[0].error);
|
||||
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
|
||||
} else {
|
||||
setSecondaryProgressBarData({
|
||||
icon: "file",
|
||||
visible: true,
|
||||
percent: 100,
|
||||
label: t("Convert"),
|
||||
alert: false,
|
||||
});
|
||||
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
|
||||
const newFilter = filter.clone();
|
||||
fetchFiles(selectedFolderId, newFilter)
|
||||
.catch((err) => {
|
||||
setSecondaryProgressBarData({
|
||||
visible: true,
|
||||
alert: true,
|
||||
});
|
||||
//toastr.error(err);
|
||||
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onConvert = () => {
|
||||
const { item, t, setSecondaryProgressBarData } = this.props;
|
||||
setSecondaryProgressBarData({
|
||||
icon: "file",
|
||||
visible: true,
|
||||
percent: 0,
|
||||
label: t("Convert"),
|
||||
alert: false,
|
||||
});
|
||||
this.setState({ showConvertDialog: false }, () =>
|
||||
convertFile(item.id).then((convertRes) => {
|
||||
if (convertRes && convertRes[0] && convertRes[0].progress !== 100) {
|
||||
this.getConvertProgress(item.id);
|
||||
}
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
onClickLock = () => {
|
||||
const { item } = this.props;
|
||||
const { locked, id } = item;
|
||||
this.props.lockFileAction(id, !locked).catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
onClickFavorite = () => {
|
||||
const { t, item } = this.props;
|
||||
this.props
|
||||
.setFavoriteAction("remove", item.id)
|
||||
.then(() => toastr.success(t("RemovedFromFavorites")))
|
||||
.catch((err) => toastr.error(err));
|
||||
};
|
||||
render() {
|
||||
const {
|
||||
t,
|
||||
item,
|
||||
isTrashFolder,
|
||||
isLoading,
|
||||
isMobile,
|
||||
canWebEdit,
|
||||
/* canConvert,*/
|
||||
sectionWidth,
|
||||
fileActionId,
|
||||
fileActionExt,
|
||||
} = this.props;
|
||||
const { itemTitle, showConvertDialog } = this.state;
|
||||
const {
|
||||
contentLength,
|
||||
updated,
|
||||
createdBy,
|
||||
fileExst,
|
||||
filesCount,
|
||||
foldersCount,
|
||||
fileStatus,
|
||||
id,
|
||||
versionGroup,
|
||||
locked,
|
||||
providerKey,
|
||||
} = item;
|
||||
const titleWithoutExt = getTitleWithoutExst(item);
|
||||
const fileOwner =
|
||||
createdBy &&
|
||||
((this.props.viewer.id === createdBy.id && t("AuthorMe")) ||
|
||||
createdBy.displayName);
|
||||
const updatedDate = updated && this.getStatusByDate();
|
||||
|
||||
const accessToEdit =
|
||||
item.access === ShareAccessRights.FullAccess ||
|
||||
item.access === ShareAccessRights.None; // TODO: fix access type for owner (now - None)
|
||||
const isEdit = id === fileActionId && fileExst === fileActionExt;
|
||||
|
||||
const linkStyles = isTrashFolder //|| window.innerWidth <= 1024
|
||||
? { noHover: true }
|
||||
: { onClick: this.onFilesClick };
|
||||
|
||||
const newItems = item.new || fileStatus === 2;
|
||||
const showNew = !!newItems;
|
||||
|
||||
return isEdit ? (
|
||||
<EditingWrapperComponent
|
||||
itemTitle={itemTitle}
|
||||
okIcon={okIcon}
|
||||
cancelIcon={cancelIcon}
|
||||
renameTitle={this.renameTitle}
|
||||
onClickUpdateItem={this.onClickUpdateItem}
|
||||
cancelUpdateItem={this.cancelUpdateItem}
|
||||
itemId={id}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{showConvertDialog && (
|
||||
<ConvertDialog
|
||||
visible={showConvertDialog}
|
||||
onClose={this.setConvertDialogVisible}
|
||||
onConvert={this.onConvert}
|
||||
/>
|
||||
)}
|
||||
<SimpleFilesRowContent
|
||||
sectionWidth={sectionWidth}
|
||||
isMobile={isMobile}
|
||||
sideColor={sideColor}
|
||||
isFile={fileExst || contentLength}
|
||||
//onClick={this.onMobileRowClick}
|
||||
>
|
||||
<Link
|
||||
containerWidth="55%"
|
||||
type="page"
|
||||
title={titleWithoutExt}
|
||||
fontWeight="600"
|
||||
fontSize="15px"
|
||||
{...linkStyles}
|
||||
color="#333"
|
||||
isTextOverflow
|
||||
>
|
||||
{titleWithoutExt}
|
||||
</Link>
|
||||
<>
|
||||
{fileExst ? (
|
||||
<div className="badges">
|
||||
<Text
|
||||
className="badge-ext"
|
||||
as="span"
|
||||
color="#A3A9AE"
|
||||
fontSize="15px"
|
||||
fontWeight={600}
|
||||
title={fileExst}
|
||||
truncate={true}
|
||||
>
|
||||
{fileExst}
|
||||
</Text>
|
||||
{/* TODO: Uncomment after fix conversation {canConvert && !isTrashFolder && (
|
||||
<IconButton
|
||||
onClick={this.setConvertDialogVisible}
|
||||
iconName="FileActionsConvertIcon"
|
||||
className="badge"
|
||||
size="small"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
hoverColor="#3B72A7"
|
||||
/>
|
||||
)} */}
|
||||
{canWebEdit && !isTrashFolder && accessToEdit && (
|
||||
<IconButton
|
||||
onClick={this.onFilesClick}
|
||||
iconName="/static/images/access.edit.react.svg"
|
||||
className="badge"
|
||||
size="small"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
hoverColor="#3B72A7"
|
||||
/>
|
||||
)}
|
||||
{locked && (
|
||||
<StyledFileActionsLockedIcon
|
||||
className="badge lock-file"
|
||||
size="small"
|
||||
data-id={item.id}
|
||||
data-locked={true}
|
||||
onClick={this.onClickLock}
|
||||
/>
|
||||
)}
|
||||
{fileStatus === 32 && !isTrashFolder && (
|
||||
<StyledFavoriteIcon
|
||||
className="favorite"
|
||||
size="small"
|
||||
data-action="remove"
|
||||
data-id={item.id}
|
||||
data-title={item.title}
|
||||
onClick={this.onClickFavorite}
|
||||
/>
|
||||
)}
|
||||
{fileStatus === 1 && (
|
||||
<StyledFileActionsConvertEditDocIcon
|
||||
className="badge"
|
||||
size="small"
|
||||
/>
|
||||
)}
|
||||
{versionGroup > 1 && (
|
||||
<Badge
|
||||
className="badge-version"
|
||||
backgroundColor="#A3A9AE"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={t("Version", {
|
||||
version: versionGroup,
|
||||
})}
|
||||
maxWidth="50px"
|
||||
onClick={this.onShowVersionHistory}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)}
|
||||
{showNew && (
|
||||
<Badge
|
||||
className="badge-version"
|
||||
backgroundColor="#ED7309"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={t("New")}
|
||||
maxWidth="50px"
|
||||
onClick={this.onBadgeClick}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="badges">
|
||||
{showNew && (
|
||||
<Badge
|
||||
className="badge-version"
|
||||
backgroundColor="#ED7309"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={newItems}
|
||||
maxWidth="50px"
|
||||
onClick={this.onBadgeClick}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
<Text
|
||||
containerMinWidth="120px"
|
||||
containerWidth="15%"
|
||||
as="div"
|
||||
color={sideColor}
|
||||
fontSize="12px"
|
||||
fontWeight={400}
|
||||
title={fileOwner}
|
||||
truncate={true}
|
||||
>
|
||||
{fileOwner}
|
||||
</Text>
|
||||
<Text
|
||||
containerMinWidth="200px"
|
||||
containerWidth="15%"
|
||||
title={updatedDate}
|
||||
fontSize="12px"
|
||||
fontWeight={400}
|
||||
color={sideColor}
|
||||
className="row_update-text"
|
||||
>
|
||||
{(fileExst || contentLength || !providerKey) &&
|
||||
updatedDate &&
|
||||
updatedDate}
|
||||
</Text>
|
||||
<Text
|
||||
containerMinWidth="90px"
|
||||
containerWidth="10%"
|
||||
as="div"
|
||||
color={sideColor}
|
||||
fontSize="12px"
|
||||
fontWeight={400}
|
||||
title=""
|
||||
truncate={true}
|
||||
>
|
||||
{fileExst || contentLength
|
||||
? contentLength
|
||||
: !providerKey
|
||||
? `${t("TitleDocuments")}: ${filesCount} | ${t(
|
||||
"TitleSubfolders"
|
||||
)}: ${foldersCount}`
|
||||
: ""}
|
||||
</Text>
|
||||
</SimpleFilesRowContent>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default inject(
|
||||
(
|
||||
{
|
||||
auth,
|
||||
filesStore,
|
||||
formatsStore,
|
||||
uploadDataStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
filesActionsStore,
|
||||
mediaViewerDataStore,
|
||||
versionHistoryStore,
|
||||
dialogsStore,
|
||||
},
|
||||
{ item }
|
||||
) => {
|
||||
const { replaceFileStream, setEncryptionAccess } = auth;
|
||||
const { culture, isDesktopClient, isTabletView } = auth.settingsStore;
|
||||
const { secondaryProgressDataStore } = uploadDataStore;
|
||||
const { setIsVerHistoryPanel, fetchFileVersions } = versionHistoryStore;
|
||||
const {
|
||||
iconFormatsStore,
|
||||
mediaViewersFormatsStore,
|
||||
docserviceStore,
|
||||
} = formatsStore;
|
||||
|
||||
const {
|
||||
fetchFiles,
|
||||
filter,
|
||||
createFile,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
createFolder,
|
||||
openDocEditor,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
updateFileBadge,
|
||||
} = filesStore;
|
||||
|
||||
const {
|
||||
isRecycleBinFolder,
|
||||
isPrivacyFolder,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
updateRootBadge,
|
||||
} = treeFoldersStore;
|
||||
|
||||
const {
|
||||
type: fileActionType,
|
||||
extension: fileActionExt,
|
||||
id: fileActionId,
|
||||
} = filesStore.fileActionStore;
|
||||
|
||||
const {
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
} = secondaryProgressDataStore;
|
||||
|
||||
const canWebEdit = docserviceStore.canWebEdit(item.fileExst);
|
||||
const canConvert = docserviceStore.canConvert(item.fileExst);
|
||||
const isVideo = mediaViewersFormatsStore.isVideo(item.fileExst);
|
||||
const isImage = iconFormatsStore.isImage(item.fileExst);
|
||||
const isSound = iconFormatsStore.isSound(item.fileExst);
|
||||
|
||||
const { setMediaViewerData } = mediaViewerDataStore;
|
||||
const {
|
||||
editCompleteAction,
|
||||
lockFileAction,
|
||||
setFavoriteAction,
|
||||
markAsRead,
|
||||
} = filesActionsStore;
|
||||
|
||||
const { setNewFilesPanelVisible, setNewFilesIds } = dialogsStore;
|
||||
|
||||
return {
|
||||
isDesktop: isDesktopClient,
|
||||
isTabletView,
|
||||
homepage: config.homepage,
|
||||
viewer: auth.userStore.user,
|
||||
culture,
|
||||
fileActionId,
|
||||
fileActionType,
|
||||
fileActionExt,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
selectedFolderPathParts: selectedFolderStore.pathParts,
|
||||
parentFolder: selectedFolderStore.parentId,
|
||||
isLoading,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
filter,
|
||||
canWebEdit,
|
||||
canConvert,
|
||||
isVideo,
|
||||
isImage,
|
||||
isSound,
|
||||
expandedKeys,
|
||||
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
setSecondaryProgressBarData,
|
||||
clearSecondaryProgressData,
|
||||
createFile,
|
||||
createFolder,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
replaceFileStream,
|
||||
setEncryptionAccess,
|
||||
addExpandedKeys,
|
||||
openDocEditor,
|
||||
editCompleteAction,
|
||||
lockFileAction,
|
||||
setFavoriteAction,
|
||||
setMediaViewerData,
|
||||
setIsVerHistoryPanel,
|
||||
fetchFileVersions,
|
||||
markAsRead,
|
||||
setNewFilesPanelVisible,
|
||||
setNewFilesIds,
|
||||
updateRootBadge,
|
||||
updateFileBadge,
|
||||
};
|
||||
}
|
||||
)(withRouter(withTranslation("Home")(observer(FilesRowContent))));
|
@ -1,721 +0,0 @@
|
||||
import React, { useCallback } from "react";
|
||||
import { ReactSVG } from "react-svg";
|
||||
import styled from "styled-components";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import IconButton from "@appserver/components/icon-button";
|
||||
import Text from "@appserver/components/text";
|
||||
import DragAndDrop from "@appserver/components/drag-and-drop";
|
||||
import Row from "@appserver/components/row";
|
||||
import FilesRowContent from "./FilesRowContent";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import toastr from "studio/toastr";
|
||||
import { FileAction, AppServerConfig } from "@appserver/common/constants";
|
||||
import copy from "copy-to-clipboard";
|
||||
import config from "../../../../../../../package.json";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
import { createSelectable } from "react-selectable-fast";
|
||||
|
||||
const StyledSimpleFilesRow = styled(Row)`
|
||||
margin-top: -2px;
|
||||
${(props) =>
|
||||
!props.contextOptions &&
|
||||
`
|
||||
& > div:last-child {
|
||||
width: 0px;
|
||||
}
|
||||
`}
|
||||
|
||||
.share-button-icon {
|
||||
margin-right: 7px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.share-button:hover,
|
||||
.share-button-icon:hover {
|
||||
cursor: pointer;
|
||||
color: #657077;
|
||||
path {
|
||||
fill: #657077;
|
||||
}
|
||||
}
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
|
||||
@media (max-width: 1312px) {
|
||||
.share-button {
|
||||
padding-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.styled-element {
|
||||
margin-right: 7px;
|
||||
}
|
||||
`;
|
||||
|
||||
const EncryptedFileIcon = styled.div`
|
||||
background: url("images/security.svg") no-repeat 0 0 / 16px 16px transparent;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
margin-top: 14px;
|
||||
margin-left: ${(props) => (props.isEdit ? "40px" : "12px")};
|
||||
`;
|
||||
|
||||
const svgLoader = () => <div style={{ width: "24px" }}></div>;
|
||||
|
||||
const SimpleFilesRow = createSelectable((props) => {
|
||||
const {
|
||||
t,
|
||||
item,
|
||||
sectionWidth,
|
||||
actionType,
|
||||
actionExtension,
|
||||
isPrivacy,
|
||||
isRecycleBin,
|
||||
dragging,
|
||||
checked,
|
||||
canShare,
|
||||
isFolder,
|
||||
draggable,
|
||||
isRootFolder,
|
||||
homepage,
|
||||
isTabletView,
|
||||
actionId,
|
||||
selectedFolderId,
|
||||
|
||||
setSharingPanelVisible,
|
||||
setChangeOwnerPanelVisible,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
setRemoveItem,
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
openDocEditor,
|
||||
setIsVerHistoryPanel,
|
||||
fetchFileVersions,
|
||||
setAction,
|
||||
deleteFileAction,
|
||||
deleteFolderAction,
|
||||
lockFileAction,
|
||||
duplicateAction,
|
||||
finalizeVersionAction,
|
||||
setFavoriteAction,
|
||||
openLocationAction,
|
||||
selectRowAction,
|
||||
setThirdpartyInfo,
|
||||
setMediaViewerData,
|
||||
setDragging,
|
||||
setStartDrag,
|
||||
startUpload,
|
||||
onSelectItem,
|
||||
history,
|
||||
setTooltipPosition,
|
||||
setDownloadDialogVisible,
|
||||
downloadAction,
|
||||
confirmDelete,
|
||||
setDeleteDialogVisible,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
id,
|
||||
title,
|
||||
fileExst,
|
||||
contentLength,
|
||||
shared,
|
||||
access,
|
||||
contextOptions,
|
||||
icon,
|
||||
providerKey,
|
||||
folderId,
|
||||
viewUrl,
|
||||
webUrl,
|
||||
canOpenPlayer,
|
||||
locked,
|
||||
parentId,
|
||||
} = item;
|
||||
|
||||
const isThirdPartyFolder = providerKey && isRootFolder;
|
||||
|
||||
const onContentRowSelect = (checked, file) => {
|
||||
if (!file) return;
|
||||
|
||||
selectRowAction(checked, file);
|
||||
};
|
||||
|
||||
const onClickShare = () => {
|
||||
onSelectItem(item);
|
||||
setSharingPanelVisible(true);
|
||||
};
|
||||
const onOwnerChange = () => setChangeOwnerPanelVisible(true);
|
||||
const onMoveAction = () => setMoveToPanelVisible(true);
|
||||
const onCopyAction = () => setCopyPanelVisible(true);
|
||||
|
||||
const getSharedButton = (shared) => {
|
||||
const color = shared ? "#657077" : "#a3a9ae";
|
||||
return (
|
||||
<Text
|
||||
className="share-button"
|
||||
as="span"
|
||||
title={t("Share")}
|
||||
fontSize="12px"
|
||||
fontWeight={600}
|
||||
color={color}
|
||||
display="inline-flex"
|
||||
onClick={onClickShare}
|
||||
>
|
||||
<IconButton
|
||||
className="share-button-icon"
|
||||
color={color}
|
||||
hoverColor="#657077"
|
||||
size={18}
|
||||
iconName="images/catalog.shared.react.svg"
|
||||
/>
|
||||
{t("Share")}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
const getItemIcon = (isEdit) => {
|
||||
return (
|
||||
<>
|
||||
<ReactSVG
|
||||
className={`react-svg-icon${isEdit ? " is-edit" : ""}`}
|
||||
src={icon}
|
||||
loading={svgLoader}
|
||||
/>
|
||||
{isPrivacy && fileExst && <EncryptedFileIcon isEdit={isEdit} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const onOpenLocation = () => {
|
||||
const locationId = isFolder ? id : folderId;
|
||||
openLocationAction(locationId, isFolder);
|
||||
};
|
||||
|
||||
const showVersionHistory = () => {
|
||||
if (!isTabletView) {
|
||||
fetchFileVersions(id + "");
|
||||
setIsVerHistoryPanel(true);
|
||||
} else {
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, homepage, `/${id}/history`)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const finalizeVersion = () =>
|
||||
finalizeVersionAction(id).catch((err) => toastr.error(err));
|
||||
|
||||
const onClickFavorite = (e) => {
|
||||
const data = (e.currentTarget && e.currentTarget.dataset) || e;
|
||||
const { action } = data;
|
||||
|
||||
setFavoriteAction(action, id)
|
||||
.then(() =>
|
||||
action === "mark"
|
||||
? toastr.success(t("MarkedAsFavorite"))
|
||||
: toastr.success(t("RemovedFromFavorites"))
|
||||
)
|
||||
.catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
const lockFile = () =>
|
||||
lockFileAction(id, !locked).catch((err) => toastr.error(err));
|
||||
|
||||
const onClickLinkForPortal = () => {
|
||||
const isFile = !!fileExst;
|
||||
copy(
|
||||
isFile
|
||||
? canOpenPlayer
|
||||
? `${window.location.href}&preview=${id}`
|
||||
: webUrl
|
||||
: `${window.location.origin + homepage}/filter?folder=${id}`
|
||||
);
|
||||
|
||||
toastr.success(t("LinkCopySuccess"));
|
||||
};
|
||||
|
||||
const onClickLinkEdit = () => openDocEditor(id, providerKey);
|
||||
|
||||
const onClickDownload = () => {
|
||||
const isFile = !!fileExst && contentLength;
|
||||
isFile
|
||||
? window.open(viewUrl, "_blank")
|
||||
: downloadAction(t("ArchivingData")).catch((err) => toastr.error(err));
|
||||
};
|
||||
|
||||
const onClickDownloadAs = () => setDownloadDialogVisible(true);
|
||||
|
||||
const onDuplicate = () =>
|
||||
duplicateAction(item, t("CopyOperation")).catch((err) => toastr.error(err));
|
||||
|
||||
const onClickRename = () => {
|
||||
setAction({
|
||||
type: FileAction.Rename,
|
||||
extension: fileExst,
|
||||
id,
|
||||
});
|
||||
};
|
||||
|
||||
const onChangeThirdPartyInfo = () => setThirdpartyInfo(providerKey);
|
||||
|
||||
const onMediaFileClick = (fileId) => {
|
||||
const itemId = typeof fileId !== "object" ? fileId : id;
|
||||
setMediaViewerData({ visible: true, id: itemId });
|
||||
};
|
||||
|
||||
const onClickDelete = () => {
|
||||
if (isThirdPartyFolder) {
|
||||
const splitItem = id.split("-");
|
||||
setRemoveItem({ id: splitItem[splitItem.length - 1], title });
|
||||
setDeleteThirdPartyDialogVisible(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirmDelete) {
|
||||
setDeleteDialogVisible(true);
|
||||
} else {
|
||||
const translations = {
|
||||
deleteOperation: t("DeleteOperation"),
|
||||
};
|
||||
|
||||
fileExst || contentLength
|
||||
? deleteFileAction(id, folderId, translations)
|
||||
.then(() => toastr.success(t("FileRemoved")))
|
||||
.catch((err) => toastr.error(err))
|
||||
: deleteFolderAction(id, parentId, translations)
|
||||
.then(() => toastr.success(t("FolderRemoved")))
|
||||
.catch((err) => toastr.error(err));
|
||||
}
|
||||
};
|
||||
|
||||
const rowContextClick = () => {
|
||||
onSelectItem(item);
|
||||
};
|
||||
|
||||
const getFilesContextOptions = useCallback(() => {
|
||||
const isSharable = access !== 1 && access !== 0;
|
||||
return contextOptions.map((option) => {
|
||||
switch (option) {
|
||||
case "open":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Open"),
|
||||
icon: "images/catalog.folder.react.svg",
|
||||
onClick: onOpenLocation,
|
||||
disabled: false,
|
||||
};
|
||||
case "show-version-history":
|
||||
return {
|
||||
key: option,
|
||||
label: t("ShowVersionHistory"),
|
||||
icon: "images/history.react.svg",
|
||||
onClick: showVersionHistory,
|
||||
disabled: false,
|
||||
};
|
||||
case "finalize-version":
|
||||
return {
|
||||
key: option,
|
||||
label: t("FinalizeVersion"),
|
||||
icon: "images/history-finalized.react.svg",
|
||||
onClick: finalizeVersion,
|
||||
disabled: false,
|
||||
};
|
||||
case "separator0":
|
||||
case "separator1":
|
||||
case "separator2":
|
||||
case "separator3":
|
||||
return { key: option, isSeparator: true };
|
||||
case "open-location":
|
||||
return {
|
||||
key: option,
|
||||
label: t("OpenLocation"),
|
||||
icon: "images/download-as.react.svg",
|
||||
onClick: onOpenLocation,
|
||||
disabled: false,
|
||||
};
|
||||
case "mark-as-favorite":
|
||||
return {
|
||||
key: option,
|
||||
label: t("MarkAsFavorite"),
|
||||
icon: "images/favorites.react.svg",
|
||||
onClick: onClickFavorite,
|
||||
disabled: false,
|
||||
"data-action": "mark",
|
||||
action: "mark",
|
||||
};
|
||||
case "block-unblock-version":
|
||||
return {
|
||||
key: option,
|
||||
label: t("UnblockVersion"),
|
||||
icon: "images/lock.react.svg",
|
||||
onClick: lockFile,
|
||||
disabled: false,
|
||||
};
|
||||
case "sharing-settings":
|
||||
return {
|
||||
key: option,
|
||||
label: t("SharingSettings"),
|
||||
icon: "images/catalog.shared.react.svg",
|
||||
onClick: onClickShare,
|
||||
disabled: isSharable,
|
||||
};
|
||||
case "send-by-email":
|
||||
return {
|
||||
key: option,
|
||||
label: t("SendByEmail"),
|
||||
icon: "/static/images/mail.react.svg",
|
||||
disabled: true,
|
||||
};
|
||||
case "owner-change":
|
||||
return {
|
||||
key: option,
|
||||
label: t("ChangeOwner"),
|
||||
icon: "images/catalog.user.react.svg",
|
||||
onClick: onOwnerChange,
|
||||
disabled: false,
|
||||
};
|
||||
case "link-for-portal-users":
|
||||
return {
|
||||
key: option,
|
||||
label: t("LinkForPortalUsers"),
|
||||
icon: "/static/images/invitation.link.react.svg",
|
||||
onClick: onClickLinkForPortal,
|
||||
disabled: false,
|
||||
};
|
||||
case "edit":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Edit"),
|
||||
icon: "/static/images/access.edit.react.svg",
|
||||
onClick: onClickLinkEdit,
|
||||
disabled: false,
|
||||
};
|
||||
case "preview":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Preview"),
|
||||
icon: "EyeIcon",
|
||||
onClick: onClickLinkEdit,
|
||||
disabled: true,
|
||||
};
|
||||
case "view":
|
||||
return {
|
||||
key: option,
|
||||
label: t("View"),
|
||||
icon: "/static/images/eye.react.svg",
|
||||
onClick: onMediaFileClick,
|
||||
disabled: false,
|
||||
};
|
||||
case "download":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Download"),
|
||||
icon: "images/download.react.svg",
|
||||
onClick: onClickDownload,
|
||||
disabled: false,
|
||||
};
|
||||
case "download-as":
|
||||
return {
|
||||
key: option,
|
||||
label: t("DownloadAs"),
|
||||
icon: "images/download-as.react.svg",
|
||||
onClick: onClickDownloadAs,
|
||||
disabled: false,
|
||||
};
|
||||
case "move-to":
|
||||
return {
|
||||
key: option,
|
||||
label: t("MoveTo"),
|
||||
icon: "images/move.react.svg",
|
||||
onClick: onMoveAction,
|
||||
disabled: false,
|
||||
};
|
||||
case "restore":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Restore"),
|
||||
icon: "images/move.react.svg",
|
||||
onClick: onMoveAction,
|
||||
disabled: false,
|
||||
};
|
||||
case "copy-to":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Copy"),
|
||||
icon: "/static/images/copy.react.svg",
|
||||
onClick: onCopyAction,
|
||||
disabled: false,
|
||||
};
|
||||
case "copy":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Duplicate"),
|
||||
icon: "/static/images/copy.react.svg",
|
||||
onClick: onDuplicate,
|
||||
disabled: false,
|
||||
};
|
||||
case "rename":
|
||||
return {
|
||||
key: option,
|
||||
label: t("Rename"),
|
||||
icon: "images/rename.react.svg",
|
||||
onClick: onClickRename,
|
||||
disabled: false,
|
||||
};
|
||||
case "change-thirdparty-info":
|
||||
return {
|
||||
key: option,
|
||||
label: t("ThirdPartyInfo"),
|
||||
icon: "/static/images/access.edit.react.svg",
|
||||
onClick: onChangeThirdPartyInfo,
|
||||
disabled: false,
|
||||
};
|
||||
case "delete":
|
||||
return {
|
||||
key: option,
|
||||
label: isThirdPartyFolder ? t("DeleteThirdParty") : t("Delete"),
|
||||
icon: "/static/images/catalog.trash.react.svg",
|
||||
onClick: onClickDelete,
|
||||
disabled: false,
|
||||
};
|
||||
case "remove-from-favorites":
|
||||
return {
|
||||
key: option,
|
||||
label: t("RemoveFromFavorites"),
|
||||
icon: "images/favorites.react.svg",
|
||||
onClick: onClickFavorite,
|
||||
disabled: false,
|
||||
"data-action": "remove",
|
||||
action: "remove",
|
||||
};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
}, [contextOptions, item]);
|
||||
|
||||
const onDropZoneUpload = (files, uploadToFolder) => {
|
||||
const folderId = uploadToFolder ? uploadToFolder : selectedFolderId;
|
||||
|
||||
dragging && setDragging(false);
|
||||
startUpload(files, folderId, t);
|
||||
};
|
||||
|
||||
const onDrop = (items) => {
|
||||
if (!fileExst) {
|
||||
onDropZoneUpload(items, id);
|
||||
} else {
|
||||
onDropZoneUpload(items, selectedFolderId);
|
||||
}
|
||||
};
|
||||
|
||||
const onMouseDown = (e) => {
|
||||
if (!draggable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
window.innerWidth < 1025 ||
|
||||
e.target.tagName === "rect" ||
|
||||
e.target.tagName === "path"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const mouseButton = e.which
|
||||
? e.which !== 1
|
||||
: e.button
|
||||
? e.button !== 0
|
||||
: false;
|
||||
const label = e.currentTarget.getAttribute("label");
|
||||
if (mouseButton || e.currentTarget.tagName !== "DIV" || label) {
|
||||
return;
|
||||
}
|
||||
|
||||
setTooltipPosition(e.pageX, e.pageY);
|
||||
setStartDrag(true);
|
||||
};
|
||||
|
||||
const isMobile = sectionWidth < 500;
|
||||
const isEdit =
|
||||
!!actionType && actionId === id && fileExst === actionExtension;
|
||||
const contextOptionsProps =
|
||||
!isEdit && contextOptions && contextOptions.length > 0
|
||||
? {
|
||||
contextOptions: getFilesContextOptions(),
|
||||
}
|
||||
: {};
|
||||
|
||||
const isDragging = isFolder && access < 2 && !isRecycleBin;
|
||||
const checkedProps = isEdit || id <= 0 ? {} : { checked };
|
||||
const element = getItemIcon(isEdit || id <= 0);
|
||||
const displayShareButton = isMobile ? "26px" : !canShare ? "38px" : "96px";
|
||||
let className = isDragging ? " droppable" : "";
|
||||
if (draggable) className += " draggable not-selectable";
|
||||
|
||||
let value = fileExst || contentLength ? `file_${id}` : `folder_${id}`;
|
||||
value += draggable ? "_draggable" : "";
|
||||
|
||||
const sharedButton =
|
||||
!canShare || (isPrivacy && !fileExst) || isEdit || id <= 0 || isMobile
|
||||
? null
|
||||
: getSharedButton(shared);
|
||||
|
||||
return (
|
||||
<div ref={props.selectableRef}>
|
||||
<DragAndDrop
|
||||
data-title={item.title}
|
||||
value={value}
|
||||
className={className}
|
||||
onDrop={onDrop}
|
||||
onMouseDown={onMouseDown}
|
||||
dragging={dragging && isDragging}
|
||||
{...contextOptionsProps}
|
||||
>
|
||||
<StyledSimpleFilesRow
|
||||
key={id}
|
||||
data={item}
|
||||
element={element}
|
||||
sectionWidth={sectionWidth}
|
||||
contentElement={sharedButton}
|
||||
onSelect={onContentRowSelect}
|
||||
rowContextClick={rowContextClick}
|
||||
isPrivacy={isPrivacy}
|
||||
{...checkedProps}
|
||||
{...contextOptionsProps}
|
||||
contextButtonSpacerWidth={displayShareButton}
|
||||
>
|
||||
<FilesRowContent item={item} sectionWidth={sectionWidth} />
|
||||
</StyledSimpleFilesRow>
|
||||
</DragAndDrop>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default inject(
|
||||
(
|
||||
{
|
||||
auth,
|
||||
filesStore,
|
||||
treeFoldersStore,
|
||||
selectedFolderStore,
|
||||
dialogsStore,
|
||||
versionHistoryStore,
|
||||
filesActionsStore,
|
||||
mediaViewerDataStore,
|
||||
uploadDataStore,
|
||||
settingsStore,
|
||||
},
|
||||
{ item }
|
||||
) => {
|
||||
const { isTabletView } = auth.settingsStore;
|
||||
const { type, extension, id } = filesStore.fileActionStore;
|
||||
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
|
||||
|
||||
const {
|
||||
setSharingPanelVisible,
|
||||
setChangeOwnerPanelVisible,
|
||||
setRemoveItem,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
setDownloadDialogVisible,
|
||||
setDeleteDialogVisible,
|
||||
} = dialogsStore;
|
||||
|
||||
const {
|
||||
selection,
|
||||
canShare,
|
||||
openDocEditor,
|
||||
fileActionStore,
|
||||
dragging,
|
||||
setDragging,
|
||||
setStartDrag,
|
||||
setTooltipPosition,
|
||||
isFileSelected,
|
||||
} = filesStore;
|
||||
|
||||
const { isRootFolder, id: selectedFolderId } = selectedFolderStore;
|
||||
const { setIsVerHistoryPanel, fetchFileVersions } = versionHistoryStore;
|
||||
const { setAction } = fileActionStore;
|
||||
|
||||
const selectedItem = selection.find(
|
||||
(x) => x.id === item.id && x.fileExst === item.fileExst
|
||||
);
|
||||
|
||||
const isFolder = selectedItem
|
||||
? false
|
||||
: item.fileExst || item.contentLength
|
||||
? false
|
||||
: true;
|
||||
|
||||
const draggable =
|
||||
!isRecycleBinFolder && selectedItem && selectedItem.id !== id;
|
||||
|
||||
const {
|
||||
deleteFileAction,
|
||||
deleteFolderAction,
|
||||
lockFileAction,
|
||||
finalizeVersionAction,
|
||||
duplicateAction,
|
||||
setFavoriteAction,
|
||||
openLocationAction,
|
||||
selectRowAction,
|
||||
setThirdpartyInfo,
|
||||
onSelectItem,
|
||||
downloadAction,
|
||||
} = filesActionsStore;
|
||||
|
||||
const { setMediaViewerData } = mediaViewerDataStore;
|
||||
const { startUpload } = uploadDataStore;
|
||||
|
||||
return {
|
||||
dragging,
|
||||
actionType: type,
|
||||
actionExtension: extension,
|
||||
isPrivacy: isPrivacyFolder,
|
||||
isRecycleBin: isRecycleBinFolder,
|
||||
isRootFolder,
|
||||
canShare,
|
||||
checked: isFileSelected(item.id, item.parentId),
|
||||
isFolder,
|
||||
draggable,
|
||||
isItemsSelected: !!selection.length,
|
||||
homepage: config.homepage,
|
||||
isTabletView,
|
||||
actionId: fileActionStore.id,
|
||||
setSharingPanelVisible,
|
||||
setChangeOwnerPanelVisible,
|
||||
setRemoveItem,
|
||||
setDeleteThirdPartyDialogVisible,
|
||||
setMoveToPanelVisible,
|
||||
setCopyPanelVisible,
|
||||
setDownloadDialogVisible,
|
||||
openDocEditor,
|
||||
setIsVerHistoryPanel,
|
||||
fetchFileVersions,
|
||||
setAction,
|
||||
deleteFileAction,
|
||||
deleteFolderAction,
|
||||
lockFileAction,
|
||||
finalizeVersionAction,
|
||||
duplicateAction,
|
||||
setFavoriteAction,
|
||||
openLocationAction,
|
||||
selectRowAction,
|
||||
setThirdpartyInfo,
|
||||
setMediaViewerData,
|
||||
selectedFolderId,
|
||||
setDragging,
|
||||
setStartDrag,
|
||||
startUpload,
|
||||
onSelectItem,
|
||||
setTooltipPosition,
|
||||
downloadAction,
|
||||
confirmDelete: settingsStore.confirmDelete,
|
||||
setDeleteDialogVisible,
|
||||
};
|
||||
}
|
||||
)(withTranslation("Home")(observer(withRouter(SimpleFilesRow))));
|
@ -1,500 +0,0 @@
|
||||
import React from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { Trans, withTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import Badge from "@appserver/components/badge";
|
||||
import Link from "@appserver/components/link";
|
||||
import Text from "@appserver/components/text";
|
||||
import { markAsRead } from "@appserver/common/api/files";
|
||||
import { FileAction, AppServerConfig } from "@appserver/common/constants";
|
||||
import toastr from "studio/toastr";
|
||||
import { getTitleWithoutExst } from "../../../../../helpers/files-helpers";
|
||||
import { NewFilesPanel } from "../../../../panels";
|
||||
import EditingWrapperComponent from "./EditingWrapperComponent";
|
||||
import TileContent from "./TileContent";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import CheckIcon from "../../../../../../public/images/check.react.svg";
|
||||
import CrossIcon from "../../../../../../../../../public/images/cross.react.svg";
|
||||
import config from "../../../../../../package.json";
|
||||
import { combineUrl } from "@appserver/common/utils";
|
||||
|
||||
const SimpleFilesTileContent = styled(TileContent)`
|
||||
.rowMainContainer {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
align-self: flex-end;
|
||||
|
||||
a {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.mainIcons {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.badge-ext {
|
||||
margin-left: -8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.share-icon {
|
||||
margin-top: -4px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
display: inline-flex;
|
||||
height: auto;
|
||||
|
||||
& > div {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const okIcon = (
|
||||
<CheckIcon
|
||||
className="edit-ok-icon"
|
||||
size="scale"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
/>
|
||||
);
|
||||
|
||||
const cancelIcon = (
|
||||
<CrossIcon
|
||||
className="edit-cancel-icon"
|
||||
size="scale"
|
||||
isfill={true}
|
||||
color="#A3A9AE"
|
||||
/>
|
||||
);
|
||||
|
||||
class FilesTileContent extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
let titleWithoutExt = getTitleWithoutExst(props.item);
|
||||
|
||||
if (props.fileAction.id === -1) {
|
||||
titleWithoutExt = this.getDefaultName(props.fileAction.extension);
|
||||
}
|
||||
|
||||
this.state = {
|
||||
itemTitle: titleWithoutExt,
|
||||
editingId: props.fileAction.id,
|
||||
showNewFilesPanel: false,
|
||||
newFolderId: [],
|
||||
newItems: props.item.new,
|
||||
//loading: false
|
||||
};
|
||||
}
|
||||
|
||||
completeAction = (e) => {
|
||||
//this.setState({ loading: false }, () =>)
|
||||
this.props.onEditComplete(e);
|
||||
};
|
||||
|
||||
updateItem = (e) => {
|
||||
const {
|
||||
fileAction,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
item,
|
||||
setIsLoading,
|
||||
} = this.props;
|
||||
|
||||
const { itemTitle } = this.state;
|
||||
const originalTitle = getTitleWithoutExst(item);
|
||||
|
||||
setIsLoading(true);
|
||||
if (originalTitle === itemTitle) return this.completeAction(e);
|
||||
|
||||
item.fileExst
|
||||
? updateFile(fileAction.id, itemTitle)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => setIsLoading(false))
|
||||
: renameFolder(fileAction.id, itemTitle)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => setIsLoading(false));
|
||||
};
|
||||
|
||||
createItem = (e) => {
|
||||
const { createFile, item, setIsLoading, createFolder, t } = this.props;
|
||||
const { itemTitle } = this.state;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
if (itemTitle.trim() === "") return this.completeAction();
|
||||
|
||||
!item.fileExst
|
||||
? createFolder(item.parentId, itemTitle)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => {
|
||||
toastr.success(
|
||||
<Trans t={t} i18nKey="FolderCreated" ns="Home">
|
||||
New folder {{ itemTitle }} is created
|
||||
</Trans>
|
||||
);
|
||||
return setIsLoading(false);
|
||||
})
|
||||
: createFile(item.parentId, `${itemTitle}.${item.fileExst}`)
|
||||
.then(() => this.completeAction(e))
|
||||
.finally(() => {
|
||||
const exst = item.fileExst;
|
||||
toastr.success(
|
||||
<Trans t={t} i18nKey="FileCreated" ns="Home">
|
||||
New file {{ itemTitle }}.{{ exst }} is created
|
||||
</Trans>
|
||||
);
|
||||
return setIsLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const { fileAction } = this.props;
|
||||
if (fileAction) {
|
||||
if (fileAction.id !== prevProps.fileAction.id) {
|
||||
this.setState({ editingId: fileAction.id });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renameTitle = (e) => {
|
||||
this.setState({ itemTitle: e.target.value });
|
||||
};
|
||||
|
||||
cancelUpdateItem = (e) => {
|
||||
//this.setState({ loading: false });
|
||||
this.completeAction(e);
|
||||
};
|
||||
|
||||
onClickUpdateItem = () => {
|
||||
this.props.fileAction.type === FileAction.Create
|
||||
? this.createItem()
|
||||
: this.updateItem();
|
||||
};
|
||||
|
||||
onKeyUpUpdateItem = (e) => {
|
||||
if (e.keyCode === 13) {
|
||||
this.props.fileAction.type === FileAction.Create
|
||||
? this.createItem()
|
||||
: this.updateItem();
|
||||
}
|
||||
|
||||
if (e.keyCode === 27) return this.cancelUpdateItem();
|
||||
};
|
||||
|
||||
onFilesClick = () => {
|
||||
const { id, fileExst, viewUrl, providerKey } = this.props.item;
|
||||
const {
|
||||
filter,
|
||||
parentFolder,
|
||||
setIsLoading,
|
||||
onMediaFileClick,
|
||||
fetchFiles,
|
||||
canWebEdit,
|
||||
openDocEditor,
|
||||
isVideo,
|
||||
isImage,
|
||||
isSound,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
} = this.props;
|
||||
if (!fileExst) {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!expandedKeys.includes(parentFolder + "")) {
|
||||
addExpandedKeys(parentFolder + "");
|
||||
}
|
||||
|
||||
fetchFiles(id, filter)
|
||||
.catch((err) => {
|
||||
toastr.error(err);
|
||||
setIsLoading(false);
|
||||
})
|
||||
.finally(() => setIsLoading(false));
|
||||
} else {
|
||||
if (canWebEdit) {
|
||||
return openDocEditor(id, providerKey);
|
||||
}
|
||||
|
||||
const isOpenMedia = isImage || isSound || isVideo;
|
||||
|
||||
if (isOpenMedia) {
|
||||
onMediaFileClick(id);
|
||||
return;
|
||||
}
|
||||
|
||||
return window.open(viewUrl, "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
onMobileRowClick = (e) => {
|
||||
if (!isMobile) return;
|
||||
|
||||
this.onFilesClick();
|
||||
};
|
||||
|
||||
getStatusByDate = () => {
|
||||
const { culture, t, item, sectionWidth } = this.props;
|
||||
const { created, updated, version, fileExst } = item;
|
||||
|
||||
const title =
|
||||
version > 1
|
||||
? t("TitleModified")
|
||||
: fileExst
|
||||
? t("TitleUploaded")
|
||||
: t("TitleCreated");
|
||||
|
||||
const date = fileExst ? updated : created;
|
||||
const dateLabel = new Date(date).toLocaleString(culture);
|
||||
const mobile = (sectionWidth && sectionWidth <= 375) || isMobile;
|
||||
|
||||
return mobile ? dateLabel : `${title}: ${dateLabel}`;
|
||||
};
|
||||
|
||||
getDefaultName = (format) => {
|
||||
const { t } = this.props;
|
||||
|
||||
switch (format) {
|
||||
case "docx":
|
||||
return t("NewDocument");
|
||||
case "xlsx":
|
||||
return t("NewSpreadsheet");
|
||||
case "pptx":
|
||||
return t("NewPresentation");
|
||||
default:
|
||||
return t("NewFolder");
|
||||
}
|
||||
};
|
||||
|
||||
onShowVersionHistory = (e) => {
|
||||
const { homepage, history } = this.props;
|
||||
const fileId = e.currentTarget.dataset.id;
|
||||
|
||||
history.push(
|
||||
combineUrl(AppServerConfig.proxyURL, homepage, `/${fileId}/history`)
|
||||
);
|
||||
};
|
||||
|
||||
onBadgeClick = () => {
|
||||
const { showNewFilesPanel } = this.state;
|
||||
const {
|
||||
item,
|
||||
treeFolders,
|
||||
setTreeFolders,
|
||||
rootFolderId,
|
||||
newItems,
|
||||
filter,
|
||||
fetchFiles,
|
||||
} = this.props;
|
||||
if (item.fileExst) {
|
||||
markAsRead([], [item.id])
|
||||
.then(() => {
|
||||
const data = treeFolders;
|
||||
const dataItem = data.find((x) => x.id === rootFolderId);
|
||||
dataItem.newItems = newItems ? dataItem.newItems - 1 : 0; //////newItems
|
||||
setTreeFolders(data);
|
||||
fetchFiles(this.props.selectedFolderId, filter.clone());
|
||||
})
|
||||
.catch((err) => toastr.error(err));
|
||||
} else {
|
||||
const newFolderId = this.props.selectedFolderPathParts;
|
||||
newFolderId.push(item.id);
|
||||
this.setState({
|
||||
showNewFilesPanel: !showNewFilesPanel,
|
||||
newFolderId,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onShowNewFilesPanel = () => {
|
||||
const { showNewFilesPanel } = this.state;
|
||||
this.setState({ showNewFilesPanel: !showNewFilesPanel });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { item, fileAction, isTrashFolder, folders } = this.props;
|
||||
const {
|
||||
itemTitle,
|
||||
editingId,
|
||||
showNewFilesPanel,
|
||||
newItems,
|
||||
newFolderId,
|
||||
} = this.state;
|
||||
const { fileExst, id } = item;
|
||||
|
||||
const titleWithoutExt = getTitleWithoutExst(item);
|
||||
|
||||
const isEdit = id === editingId && fileExst === fileAction.extension;
|
||||
const linkStyles = isTrashFolder
|
||||
? { noHover: true }
|
||||
: { onClick: this.onFilesClick };
|
||||
const showNew = item.new && item.new > 0;
|
||||
|
||||
return isEdit ? (
|
||||
<EditingWrapperComponent
|
||||
itemTitle={itemTitle}
|
||||
okIcon={okIcon}
|
||||
cancelIcon={cancelIcon}
|
||||
renameTitle={this.renameTitle}
|
||||
onKeyUpUpdateItem={this.onKeyUpUpdateItem}
|
||||
onClickUpdateItem={this.onClickUpdateItem}
|
||||
cancelUpdateItem={this.cancelUpdateItem}
|
||||
itemId={id}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
{showNewFilesPanel && (
|
||||
<NewFilesPanel
|
||||
visible={showNewFilesPanel}
|
||||
onClose={this.onShowNewFilesPanel}
|
||||
folderId={newFolderId}
|
||||
folders={folders}
|
||||
/>
|
||||
)}
|
||||
<SimpleFilesTileContent
|
||||
sideColor="#333"
|
||||
isFile={fileExst}
|
||||
onClick={this.onMobileRowClick}
|
||||
disableSideInfo
|
||||
>
|
||||
<Link
|
||||
containerWidth="100%"
|
||||
type="page"
|
||||
title={titleWithoutExt}
|
||||
fontWeight="bold"
|
||||
fontSize="15px"
|
||||
{...linkStyles}
|
||||
color="#333"
|
||||
isTextOverflow
|
||||
>
|
||||
{titleWithoutExt}
|
||||
</Link>
|
||||
<>
|
||||
{fileExst ? (
|
||||
<div className="badges">
|
||||
<Text
|
||||
className="badge-ext"
|
||||
as="span"
|
||||
color="#A3A9AE"
|
||||
fontSize="15px"
|
||||
fontWeight={600}
|
||||
title={fileExst}
|
||||
truncate={true}
|
||||
>
|
||||
{fileExst}
|
||||
</Text>
|
||||
</div>
|
||||
) : (
|
||||
<div className="badges">
|
||||
{!!showNew && (
|
||||
<Badge
|
||||
className="badge-version"
|
||||
backgroundColor="#ED7309"
|
||||
borderRadius="11px"
|
||||
color="#FFFFFF"
|
||||
fontSize="10px"
|
||||
fontWeight={800}
|
||||
label={newItems}
|
||||
maxWidth="50px"
|
||||
onClick={this.onBadgeClick}
|
||||
padding="0 5px"
|
||||
data-id={id}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</SimpleFilesTileContent>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default inject(
|
||||
(
|
||||
{ auth, filesStore, formatsStore, treeFoldersStore, selectedFolderStore },
|
||||
{ item }
|
||||
) => {
|
||||
const { culture } = auth.settingsStore;
|
||||
const {
|
||||
iconFormatsStore,
|
||||
mediaViewersFormatsStore,
|
||||
docserviceStore,
|
||||
} = formatsStore;
|
||||
const {
|
||||
folders,
|
||||
fetchFiles,
|
||||
filter,
|
||||
newRowItems,
|
||||
createFile,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
createFolder,
|
||||
setIsLoading,
|
||||
isLoading,
|
||||
dragging,
|
||||
} = filesStore;
|
||||
|
||||
const {
|
||||
treeFolders,
|
||||
setTreeFolders,
|
||||
isRecycleBinFolder,
|
||||
expandedKeys,
|
||||
addExpandedKeys,
|
||||
} = treeFoldersStore;
|
||||
|
||||
const { type, extension, id } = filesStore.fileActionStore;
|
||||
|
||||
const fileAction = { type, extension, id };
|
||||
|
||||
const canWebEdit = docserviceStore.canWebEdit(item.fileExst);
|
||||
const isVideo = mediaViewersFormatsStore.isVideo(item.fileExst);
|
||||
const isImage = iconFormatsStore.isImage(item.fileExst);
|
||||
const isSound = iconFormatsStore.isSound(item.fileExst);
|
||||
|
||||
return {
|
||||
culture,
|
||||
homepage: config.homepage,
|
||||
fileAction,
|
||||
folders,
|
||||
rootFolderId: selectedFolderStore.pathParts,
|
||||
selectedFolderId: selectedFolderStore.id,
|
||||
selectedFolderPathParts: selectedFolderStore.pathParts,
|
||||
newItems: selectedFolderStore.new,
|
||||
parentFolder: selectedFolderStore.parentId,
|
||||
isLoading,
|
||||
treeFolders,
|
||||
isTrashFolder: isRecycleBinFolder,
|
||||
filter,
|
||||
dragging,
|
||||
canWebEdit,
|
||||
isVideo,
|
||||
isImage,
|
||||
isSound,
|
||||
newRowItems,
|
||||
expandedKeys,
|
||||
|
||||
setIsLoading,
|
||||
fetchFiles,
|
||||
setTreeFolders,
|
||||
createFile,
|
||||
createFolder,
|
||||
updateFile,
|
||||
renameFolder,
|
||||
addExpandedKeys,
|
||||
};
|
||||
}
|
||||
)(withRouter(withTranslation("Home")(observer(FilesTileContent))));
|
@ -12,7 +12,7 @@ import {
|
||||
StyledHeaderContent,
|
||||
StyledBody,
|
||||
} from "../StyledPanels";
|
||||
import { SectionBodyContent } from "../../pages/VersionHistory/Section/";
|
||||
import { SectionBodyContent } from "../../../pages/VersionHistory/Section/";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import config from "../../../../package.json";
|
||||
|
||||
|
@ -0,0 +1,35 @@
|
||||
import React from "react";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import RowContainer from "@appserver/components/row-container";
|
||||
import { Consumer } from "@appserver/components/utils/context";
|
||||
import SimpleFilesRow from "./SimpleFilesRow";
|
||||
|
||||
const FilesRowContainer = ({ filesList }) => {
|
||||
return (
|
||||
<Consumer>
|
||||
{(context) => (
|
||||
<RowContainer
|
||||
className="files-row-container"
|
||||
draggable
|
||||
useReactWindow={false}
|
||||
>
|
||||
{filesList.map((item, index) => (
|
||||
<SimpleFilesRow
|
||||
key={`${item.id}_${index}`}
|
||||
item={item}
|
||||
sectionWidth={context.sectionWidth}
|
||||
/>
|
||||
))}
|
||||
</RowContainer>
|
||||
)}
|
||||
</Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ filesStore }) => {
|
||||
const { filesList } = filesStore;
|
||||
|
||||
return {
|
||||
filesList,
|
||||
};
|
||||
})(observer(FilesRowContainer));
|
@ -0,0 +1,164 @@
|
||||
import React from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import Link from "@appserver/components/link";
|
||||
import Text from "@appserver/components/text";
|
||||
import RowContent from "@appserver/components/row-content";
|
||||
|
||||
import withContent from "../../../../../HOCs/withContent";
|
||||
import withBadges from "../../../../../HOCs/withBadges";
|
||||
|
||||
const sideColor = "#A3A9AE";
|
||||
|
||||
const SimpleFilesRowContent = styled(RowContent)`
|
||||
.badge-ext {
|
||||
margin-left: -8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
margin-right: 6px;
|
||||
}
|
||||
.lock-file {
|
||||
cursor: pointer;
|
||||
}
|
||||
.badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.favorite {
|
||||
cursor: pointer;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.share-icon {
|
||||
margin-top: -4px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.row_update-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
`;
|
||||
|
||||
const FilesRowContent = ({
|
||||
t,
|
||||
item,
|
||||
sectionWidth,
|
||||
titleWithoutExt,
|
||||
updatedDate,
|
||||
fileOwner,
|
||||
linkStyles,
|
||||
isTrashFolder,
|
||||
onFilesClick,
|
||||
badgesComponent,
|
||||
}) => {
|
||||
const {
|
||||
contentLength,
|
||||
fileExst,
|
||||
filesCount,
|
||||
foldersCount,
|
||||
providerKey,
|
||||
} = item;
|
||||
|
||||
const onMobileRowClick = () => {
|
||||
if (isTrashFolder || window.innerWidth > 1024) return;
|
||||
onFilesClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SimpleFilesRowContent
|
||||
sectionWidth={sectionWidth}
|
||||
isMobile={isMobile}
|
||||
sideColor={sideColor}
|
||||
isFile={fileExst || contentLength}
|
||||
//onClick={onMobileRowClick}
|
||||
>
|
||||
<Link
|
||||
containerWidth="55%"
|
||||
type="page"
|
||||
title={titleWithoutExt}
|
||||
fontWeight="600"
|
||||
fontSize="15px"
|
||||
{...linkStyles}
|
||||
color="#333"
|
||||
isTextOverflow
|
||||
>
|
||||
{titleWithoutExt}
|
||||
</Link>
|
||||
|
||||
<div className="badges">
|
||||
{fileExst ? (
|
||||
<Text
|
||||
className="badge-ext"
|
||||
as="span"
|
||||
color="#A3A9AE"
|
||||
fontSize="15px"
|
||||
fontWeight={600}
|
||||
title={fileExst}
|
||||
truncate={true}
|
||||
>
|
||||
{fileExst}
|
||||
</Text>
|
||||
) : null}
|
||||
{badgesComponent}
|
||||
</div>
|
||||
<Text
|
||||
containerMinWidth="120px"
|
||||
containerWidth="15%"
|
||||
as="div"
|
||||
color={sideColor}
|
||||
fontSize="12px"
|
||||
fontWeight={400}
|
||||
title={fileOwner}
|
||||
truncate={true}
|
||||
>
|
||||
{fileOwner}
|
||||
</Text>
|
||||
<Text
|
||||
containerMinWidth="200px"
|
||||
containerWidth="15%"
|
||||
title={updatedDate}
|
||||
fontSize="12px"
|
||||
fontWeight={400}
|
||||
color={sideColor}
|
||||
className="row_update-text"
|
||||
>
|
||||
{(fileExst || contentLength || !providerKey) &&
|
||||
updatedDate &&
|
||||
updatedDate}
|
||||
</Text>
|
||||
<Text
|
||||
containerMinWidth="90px"
|
||||
containerWidth="10%"
|
||||
as="div"
|
||||
color={sideColor}
|
||||
fontSize="12px"
|
||||
fontWeight={400}
|
||||
title=""
|
||||
truncate={true}
|
||||
>
|
||||
{fileExst || contentLength
|
||||
? contentLength
|
||||
: !providerKey
|
||||
? `${t("TitleDocuments")}: ${filesCount} | ${t(
|
||||
"TitleSubfolders"
|
||||
)}: ${foldersCount}`
|
||||
: ""}
|
||||
</Text>
|
||||
</SimpleFilesRowContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
withTranslation("Home")(withContent(withBadges(FilesRowContent)))
|
||||
);
|
@ -0,0 +1,107 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import DragAndDrop from "@appserver/components/drag-and-drop";
|
||||
import Row from "@appserver/components/row";
|
||||
import FilesRowContent from "./FilesRowContent";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import { createSelectable } from "react-selectable-fast";
|
||||
|
||||
import withFileActions from "../../../../../HOCs/withFileActions";
|
||||
import withContextOptions from "../../../../../HOCs/withContextOptions";
|
||||
|
||||
const StyledSimpleFilesRow = styled(Row)`
|
||||
margin-top: -2px;
|
||||
${(props) =>
|
||||
!props.contextOptions &&
|
||||
`
|
||||
& > div:last-child {
|
||||
width: 0px;
|
||||
}
|
||||
`}
|
||||
|
||||
.share-button-icon {
|
||||
margin-right: 7px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.share-button:hover,
|
||||
.share-button-icon:hover {
|
||||
cursor: pointer;
|
||||
color: #657077;
|
||||
path {
|
||||
fill: #657077;
|
||||
}
|
||||
}
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
|
||||
@media (max-width: 1312px) {
|
||||
.share-button {
|
||||
padding-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.styled-element {
|
||||
margin-right: 7px;
|
||||
}
|
||||
`;
|
||||
|
||||
const SimpleFilesRow = createSelectable((props) => {
|
||||
const {
|
||||
item,
|
||||
sectionWidth,
|
||||
dragging,
|
||||
onContentRowSelect,
|
||||
rowContextClick,
|
||||
onDrop,
|
||||
onMouseDown,
|
||||
className,
|
||||
isDragging,
|
||||
value,
|
||||
displayShareButton,
|
||||
isPrivacy,
|
||||
sharedButton,
|
||||
contextOptionsProps,
|
||||
checkedProps,
|
||||
element,
|
||||
onFilesClick,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div ref={props.selectableRef}>
|
||||
<DragAndDrop
|
||||
data-title={item.title}
|
||||
value={value}
|
||||
className={className}
|
||||
onDrop={onDrop}
|
||||
onMouseDown={onMouseDown}
|
||||
dragging={dragging && isDragging}
|
||||
{...contextOptionsProps}
|
||||
>
|
||||
<StyledSimpleFilesRow
|
||||
key={item.id}
|
||||
data={item}
|
||||
element={element}
|
||||
sectionWidth={sectionWidth}
|
||||
contentElement={sharedButton}
|
||||
onSelect={onContentRowSelect}
|
||||
rowContextClick={rowContextClick}
|
||||
isPrivacy={isPrivacy}
|
||||
{...checkedProps}
|
||||
{...contextOptionsProps}
|
||||
contextButtonSpacerWidth={displayShareButton}
|
||||
>
|
||||
<FilesRowContent
|
||||
item={item}
|
||||
sectionWidth={sectionWidth}
|
||||
onFilesClick={onFilesClick}
|
||||
/>
|
||||
</StyledSimpleFilesRow>
|
||||
</DragAndDrop>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default withTranslation("Home")(
|
||||
withFileActions(withContextOptions(withRouter(SimpleFilesRow)))
|
||||
);
|
@ -0,0 +1,64 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import DragAndDrop from "@appserver/components/drag-and-drop";
|
||||
|
||||
import Tile from "./sub-components/Tile";
|
||||
import FilesTileContent from "./FilesTileContent";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import { createSelectable } from "react-selectable-fast";
|
||||
|
||||
import withFileActions from "../hoc/withFileActions";
|
||||
|
||||
const FilesTile = createSelectable((props) => {
|
||||
const {
|
||||
item,
|
||||
sectionWidth,
|
||||
dragging,
|
||||
onContentRowSelect,
|
||||
rowContextClick,
|
||||
onDrop,
|
||||
onMouseDown,
|
||||
className,
|
||||
isDragging,
|
||||
value,
|
||||
displayShareButton,
|
||||
isPrivacy,
|
||||
sharedButton,
|
||||
contextOptionsProps,
|
||||
checkedProps,
|
||||
element,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div ref={props.selectableRef}>
|
||||
<DragAndDrop
|
||||
data-title={item.title}
|
||||
value={value}
|
||||
className={className}
|
||||
onDrop={onDrop}
|
||||
onMouseDown={onMouseDown}
|
||||
dragging={dragging && isDragging}
|
||||
{...contextOptionsProps}
|
||||
>
|
||||
<Tile
|
||||
key={item.id}
|
||||
data={item}
|
||||
element={element}
|
||||
sectionWidth={sectionWidth}
|
||||
contentElement={sharedButton}
|
||||
onSelect={onContentRowSelect}
|
||||
rowContextClick={rowContextClick}
|
||||
isPrivacy={isPrivacy}
|
||||
{...checkedProps}
|
||||
{...contextOptionsProps}
|
||||
contextButtonSpacerWidth={displayShareButton}
|
||||
>
|
||||
<FilesTileContent item={item} sectionWidth={sectionWidth} />
|
||||
</Tile>
|
||||
</DragAndDrop>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default withTranslation("Home")(withFileActions(withRouter(FilesTile)));
|
@ -0,0 +1,153 @@
|
||||
import React from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
|
||||
import Link from "@appserver/components/link";
|
||||
import Text from "@appserver/components/text";
|
||||
|
||||
import TileContent from "./TileContent";
|
||||
import withContent from "../hoc/withContent";
|
||||
import Badges from "../sub-components/Badges";
|
||||
|
||||
const SimpleFilesTileContent = styled(TileContent)`
|
||||
.rowMainContainer {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
align-self: flex-end;
|
||||
|
||||
a {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.mainIcons {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.badge-ext {
|
||||
margin-left: -8px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.badges {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.share-icon {
|
||||
margin-top: -4px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
display: inline-flex;
|
||||
height: auto;
|
||||
|
||||
& > div {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const FilesTileContent = ({
|
||||
t,
|
||||
item,
|
||||
sectionWidth,
|
||||
titleWithoutExt,
|
||||
updatedDate,
|
||||
fileOwner,
|
||||
accessToEdit,
|
||||
linkStyles,
|
||||
newItems,
|
||||
showNew,
|
||||
canWebEdit,
|
||||
canConvert,
|
||||
isTrashFolder,
|
||||
onFilesClick,
|
||||
onShowVersionHistory,
|
||||
onBadgeClick,
|
||||
onClickLock,
|
||||
onClickFavorite,
|
||||
setConvertDialogVisible,
|
||||
}) => {
|
||||
const {
|
||||
contentLength,
|
||||
fileExst,
|
||||
filesCount,
|
||||
foldersCount,
|
||||
fileStatus,
|
||||
id,
|
||||
versionGroup,
|
||||
locked,
|
||||
providerKey,
|
||||
} = item;
|
||||
|
||||
const onMobileRowClick = () => {
|
||||
if (isTrashFolder || window.innerWidth > 1024) return;
|
||||
onFilesClick();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SimpleFilesTileContent
|
||||
sideColor="#333"
|
||||
isFile={fileExst}
|
||||
//onClick={onMobileRowClick}
|
||||
//disableSideInfo
|
||||
>
|
||||
<Link
|
||||
containerWidth="100%"
|
||||
type="page"
|
||||
title={titleWithoutExt}
|
||||
fontWeight="bold"
|
||||
fontSize="15px"
|
||||
{...linkStyles}
|
||||
color="#333"
|
||||
isTextOverflow
|
||||
>
|
||||
{titleWithoutExt}
|
||||
{fileExst ? (
|
||||
<Text
|
||||
className="badge-ext"
|
||||
as="span"
|
||||
color="#A3A9AE"
|
||||
fontSize="15px"
|
||||
fontWeight={600}
|
||||
title={fileExst}
|
||||
truncate={true}
|
||||
>
|
||||
{fileExst}
|
||||
</Text>
|
||||
) : null}
|
||||
</Link>
|
||||
|
||||
<div className="badges">
|
||||
<Badges
|
||||
newItems={newItems}
|
||||
item={item}
|
||||
canWebEdit={canWebEdit}
|
||||
isTrashFolder={isTrashFolder}
|
||||
canConvert={canConvert}
|
||||
accessToEdit={accessToEdit}
|
||||
showNew={showNew}
|
||||
onFilesClick={onFilesClick}
|
||||
onClickLock={onClickLock}
|
||||
onClickFavorite={onClickFavorite}
|
||||
onShowVersionHistory={onShowVersionHistory}
|
||||
onBadgeClick={onBadgeClick}
|
||||
setConvertDialogVisible={setConvertDialogVisible}
|
||||
/>
|
||||
</div>
|
||||
</SimpleFilesTileContent>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default withRouter(
|
||||
withTranslation("Home")(withContent(FilesTileContent))
|
||||
);
|
@ -1,25 +1,22 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import Loaders from "@appserver/common/components/Loaders";
|
||||
import { isMobile } from "react-device-detect";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import FilesRowContainer from "./FilesRow/FilesRowContainer";
|
||||
import FilesTileContainer from "./FilesTile/FilesTileContainer";
|
||||
import EmptyContainer from "./EmptyContainer";
|
||||
import FilesRowContainer from "./RowsView/FilesRowContainer";
|
||||
import FilesTileContainer from "./TilesView/FilesTileContainer";
|
||||
import EmptyContainer from "../../../../components/EmptyContainer";
|
||||
|
||||
import withLoader from "../../../../HOCs/withLoader";
|
||||
|
||||
let currentDroppable = null;
|
||||
|
||||
let loadTimeout = null;
|
||||
|
||||
const SectionBodyContent = (props) => {
|
||||
const {
|
||||
t,
|
||||
tReady,
|
||||
fileActionId,
|
||||
viewAs,
|
||||
firstLoad,
|
||||
isLoading,
|
||||
isEmptyFilesList,
|
||||
folderId,
|
||||
dragging,
|
||||
@ -31,31 +28,6 @@ const SectionBodyContent = (props) => {
|
||||
moveDragItems,
|
||||
} = props;
|
||||
|
||||
const [inLoad, setInLoad] = useState(false);
|
||||
|
||||
const cleanTimer = () => {
|
||||
loadTimeout && clearTimeout(loadTimeout);
|
||||
loadTimeout = null;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading) {
|
||||
cleanTimer();
|
||||
loadTimeout = setTimeout(() => {
|
||||
console.log("inLoad", true);
|
||||
setInLoad(true);
|
||||
}, 500);
|
||||
} else {
|
||||
cleanTimer();
|
||||
console.log("inLoad", false);
|
||||
setInLoad(false);
|
||||
}
|
||||
|
||||
return () => {
|
||||
cleanTimer();
|
||||
};
|
||||
}, [isLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
const customScrollElm = document.querySelector(
|
||||
"#customScrollBar > .scroll-body"
|
||||
@ -174,11 +146,7 @@ const SectionBodyContent = (props) => {
|
||||
//console.log("Files Home SectionBodyContent render", props);
|
||||
|
||||
return (!fileActionId && isEmptyFilesList) || null ? (
|
||||
firstLoad || (isMobile && inLoad) ? (
|
||||
<Loaders.Rows />
|
||||
) : (
|
||||
<EmptyContainer />
|
||||
)
|
||||
<EmptyContainer />
|
||||
) : viewAs === "tile" ? (
|
||||
<FilesTileContainer />
|
||||
) : (
|
||||
@ -194,14 +162,12 @@ export default inject(
|
||||
filesActionsStore,
|
||||
}) => {
|
||||
const {
|
||||
firstLoad,
|
||||
fileActionStore,
|
||||
filesList,
|
||||
dragging,
|
||||
setDragging,
|
||||
startDrag,
|
||||
setStartDrag,
|
||||
isLoading,
|
||||
viewAs,
|
||||
setTooltipPosition,
|
||||
} = filesStore;
|
||||
@ -209,9 +175,7 @@ export default inject(
|
||||
return {
|
||||
dragging,
|
||||
fileActionId: fileActionStore.id,
|
||||
firstLoad,
|
||||
viewAs,
|
||||
isLoading,
|
||||
isEmptyFilesList: filesList.length <= 0,
|
||||
setDragging,
|
||||
startDrag,
|
||||
@ -222,4 +186,6 @@ export default inject(
|
||||
moveDragItems: filesActionsStore.moveDragItems,
|
||||
};
|
||||
}
|
||||
)(withRouter(withTranslation("Home")(observer(SectionBodyContent))));
|
||||
)(
|
||||
withRouter(withTranslation("Home")(withLoader(observer(SectionBodyContent))))
|
||||
);
|
@ -14,7 +14,7 @@ import {
|
||||
ArticleBodyContent,
|
||||
ArticleHeaderContent,
|
||||
ArticleMainButtonContent,
|
||||
} from "../../Article";
|
||||
} from "../../components/Article";
|
||||
import {
|
||||
SectionBodyContent,
|
||||
SectionFilterContent,
|
||||
@ -22,11 +22,11 @@ import {
|
||||
SectionPagingContent,
|
||||
} from "./Section";
|
||||
|
||||
import { ConvertDialog } from "../../dialogs";
|
||||
import { ConvertDialog } from "../../components/dialogs";
|
||||
import MediaViewer from "./MediaViewer";
|
||||
import DragTooltip from "../../DragTooltip";
|
||||
import DragTooltip from "../../components/DragTooltip";
|
||||
import { observer, inject } from "mobx-react";
|
||||
import config from "../../../../package.json";
|
||||
import config from "../../../package.json";
|
||||
|
||||
class PureHome extends React.Component {
|
||||
componentDidMount() {
|
@ -7,22 +7,22 @@ import Box from "@appserver/components/box";
|
||||
import Row from "@appserver/components/row";
|
||||
import RowContainer from "@appserver/components/row-container";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import EmptyFolderContainer from "../../../Home/Section/Body/EmptyContainer/EmptyContainer";
|
||||
import BoxIcon from "../../../../../../public/images/icon_box.react.svg";
|
||||
import DropBoxIcon from "../../../../../../public/images/icon_dropbox.react.svg";
|
||||
import GoogleDriveIcon from "../../../../../../public/images/icon_google_drive.react.svg";
|
||||
import KDriveIcon from "../../../../../../public/images/icon_kdrive.react.svg";
|
||||
import NextCloudIcon from "../../../../../../public/images/icon_nextcloud.react.svg";
|
||||
import OneDriveIcon from "../../../../../../public/images/icon_onedrive.react.svg";
|
||||
import OwnCloudIcon from "../../../../../../public/images/icon_owncloud.react.svg";
|
||||
import SharePointIcon from "../../../../../../public/images/icon_sharepoint.react.svg";
|
||||
import WebDavIcon from "../../../../../../public/images/icon_webdav.react.svg";
|
||||
import YandexDiskIcon from "../../../../../../public/images/icon_yandex_disk.react.svg";
|
||||
import EmptyFolderContainer from "../../../../components/EmptyContainer/EmptyContainer";
|
||||
import BoxIcon from "../../../../../public/images/icon_box.react.svg";
|
||||
import DropBoxIcon from "../../../../../public/images/icon_dropbox.react.svg";
|
||||
import GoogleDriveIcon from "../../../../../public/images/icon_google_drive.react.svg";
|
||||
import KDriveIcon from "../../../../../public/images/icon_kdrive.react.svg";
|
||||
import NextCloudIcon from "../../../../../public/images/icon_nextcloud.react.svg";
|
||||
import OneDriveIcon from "../../../../../public/images/icon_onedrive.react.svg";
|
||||
import OwnCloudIcon from "../../../../../public/images/icon_owncloud.react.svg";
|
||||
import SharePointIcon from "../../../../../public/images/icon_sharepoint.react.svg";
|
||||
import WebDavIcon from "../../../../../public/images/icon_webdav.react.svg";
|
||||
import YandexDiskIcon from "../../../../../public/images/icon_yandex_disk.react.svg";
|
||||
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import combineUrl from "@appserver/common/utils/combineUrl";
|
||||
import AppServerConfig from "@appserver/common/constants/AppServerConfig";
|
||||
import config from "../../../../../../package.json";
|
||||
import config from "../../../../../package.json";
|
||||
import { withRouter } from "react-router";
|
||||
|
||||
const StyledBoxIcon = styled(BoxIcon)`
|
@ -6,7 +6,7 @@ import Error403 from "studio/Error403";
|
||||
import Error520 from "studio/Error520";
|
||||
import ConnectClouds from "./ConnectedClouds";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { loopTreeFolders } from "../../../../../helpers/files-helpers";
|
||||
import { loopTreeFolders } from "../../../../helpers/files-helpers";
|
||||
|
||||
const StyledSettings = styled.div`
|
||||
display: grid;
|
@ -7,10 +7,10 @@ import {
|
||||
ArticleHeaderContent,
|
||||
ArticleBodyContent,
|
||||
ArticleMainButtonContent,
|
||||
} from "../../Article";
|
||||
} from "../../components/Article";
|
||||
import { SectionHeaderContent, SectionBodyContent } from "./Section";
|
||||
import { withTranslation } from "react-i18next";
|
||||
import { setDocumentTitle } from "../../../helpers/utils";
|
||||
import { setDocumentTitle } from "../../helpers/utils";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
const PureSettings = ({
|
@ -10,7 +10,7 @@ import { withTranslation } from "react-i18next";
|
||||
import { withRouter } from "react-router";
|
||||
import VersionBadge from "./VersionBadge";
|
||||
import StyledVersionRow from "./StyledVersionRow";
|
||||
import ExternalLinkIcon from "../../../../../../public/images/external.link.react.svg";
|
||||
import ExternalLinkIcon from "../../../../../public/images/external.link.react.svg";
|
||||
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
ArticleHeaderContent,
|
||||
ArticleBodyContent,
|
||||
ArticleMainButtonContent,
|
||||
} from "../../Article";
|
||||
} from "../../components/Article";
|
||||
import { SectionHeaderContent, SectionBodyContent } from "./Section";
|
||||
//import { setDocumentTitle } from "../../../helpers/utils";
|
||||
import { inject, observer } from "mobx-react";
|
@ -976,10 +976,12 @@ namespace ASC.Files.Core.Data
|
||||
};
|
||||
|
||||
FilesDbContext.AddOrUpdate(r => r.BunchObjects, toInsert);
|
||||
FilesDbContext.SaveChanges();
|
||||
|
||||
tx.Commit(); //Commit changes
|
||||
}
|
||||
|
||||
FilesDbContext.SaveChanges();
|
||||
|
||||
|
||||
return newFolderId;
|
||||
}
|
||||
|
@ -193,6 +193,7 @@ class SectionBodyContent extends React.PureComponent {
|
||||
const providerButtons =
|
||||
providers &&
|
||||
providers.map((item) => {
|
||||
if (!providersData[item.provider]) return;
|
||||
const { icon, label, iconOptions } = providersData[item.provider];
|
||||
|
||||
if (!icon || !label) return <React.Fragment></React.Fragment>;
|
||||
@ -247,17 +248,21 @@ class SectionBodyContent extends React.PureComponent {
|
||||
return providerButtons;
|
||||
};
|
||||
|
||||
oauthDataExists = () => {
|
||||
const { providers } = this.props;
|
||||
|
||||
let existProviders = 0;
|
||||
providers && providers.length > 0;
|
||||
providers.map((item) => {
|
||||
if (!providersData[item.provider]) return;
|
||||
existProviders++;
|
||||
});
|
||||
|
||||
return !!existProviders;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
profile,
|
||||
cultures,
|
||||
culture,
|
||||
isAdmin,
|
||||
viewer,
|
||||
t,
|
||||
isSelf,
|
||||
providers,
|
||||
} = this.props;
|
||||
const { profile, cultures, culture, isAdmin, t, isSelf } = this.props;
|
||||
|
||||
const contacts = profile.contacts && getUserContacts(profile.contacts);
|
||||
const role = getUserRole(profile);
|
||||
@ -300,7 +305,7 @@ class SectionBodyContent extends React.PureComponent {
|
||||
culture={culture}
|
||||
/>
|
||||
|
||||
{isSelf && providers && providers.length > 0 && (
|
||||
{isSelf && this.oauthDataExists() && (
|
||||
<ToggleWrapper>
|
||||
<ToggleContent label={t("LoginSettings")} isOpen={true}>
|
||||
<ProviderButtonsWrapper>
|
||||
|
@ -1372,21 +1372,54 @@ namespace ASC.Api.Settings
|
||||
return FirstTimeTenantSettings.SaveData(wizardModel);
|
||||
}
|
||||
|
||||
[Read("tfaapp")]
|
||||
public IEnumerable<TfaSettings> GetTfaSettings()
|
||||
{
|
||||
var result = new List<TfaSettings>();
|
||||
|
||||
var SmsVisible = StudioSmsNotificationSettingsHelper.IsVisibleSettings();
|
||||
var SmsEnable = SmsVisible && SmsProviderManager.Enabled();
|
||||
var TfaVisible = TfaAppAuthSettings.IsVisibleSettings;
|
||||
|
||||
if (SmsVisible)
|
||||
{
|
||||
result.Add(new TfaSettings
|
||||
{
|
||||
Enabled = StudioSmsNotificationSettingsHelper.Enable,
|
||||
Id = "sms",
|
||||
Title = Resource.ButtonSmsEnable,
|
||||
Avaliable = SmsEnable
|
||||
});
|
||||
}
|
||||
|
||||
if (TfaVisible)
|
||||
{
|
||||
result.Add(new TfaSettings
|
||||
{
|
||||
Enabled = SettingsManager.Load<TfaAppAuthSettings>().EnableSetting,
|
||||
Id = "app",
|
||||
Title = Resource.ButtonTfaAppEnable,
|
||||
Avaliable = true
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[Update("tfaapp")]
|
||||
public bool TfaSettingsFromBody([FromBody]TfaModel model)
|
||||
{
|
||||
return TfaSettings(model);
|
||||
return TfaSettingsUpdate(model);
|
||||
}
|
||||
|
||||
[Update("tfaapp")]
|
||||
[Consumes("application/x-www-form-urlencoded")]
|
||||
public bool TfaSettingsFromForm([FromForm] TfaModel model)
|
||||
{
|
||||
return TfaSettings(model);
|
||||
return TfaSettingsUpdate(model);
|
||||
}
|
||||
|
||||
private bool TfaSettings(TfaModel model)
|
||||
private bool TfaSettingsUpdate(TfaModel model)
|
||||
{
|
||||
PermissionContext.DemandPermissions(SecutiryConstants.EditPortalSettings);
|
||||
|
||||
|
10
web/ASC.Web.Api/Models/TfaSettings.cs
Normal file
10
web/ASC.Web.Api/Models/TfaSettings.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace ASC.Web.Api.Models
|
||||
{
|
||||
public class TfaSettings
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public bool Avaliable { get; set; }
|
||||
}
|
||||
}
|
@ -195,10 +195,11 @@ class Confirm extends React.PureComponent {
|
||||
const providerButtons =
|
||||
providers &&
|
||||
providers.map((item, index) => {
|
||||
if (!providersData[item.provider]) return;
|
||||
const { icon, label, iconOptions, className } = providersData[
|
||||
item.provider
|
||||
];
|
||||
if (!icon) return;
|
||||
|
||||
if (item.provider === "Facebook") {
|
||||
facebookIndex = index;
|
||||
return;
|
||||
@ -223,6 +224,19 @@ class Confirm extends React.PureComponent {
|
||||
return providerButtons;
|
||||
};
|
||||
|
||||
oauthDataExists = () => {
|
||||
const { providers } = this.props;
|
||||
|
||||
let existProviders = 0;
|
||||
providers && providers.length > 0;
|
||||
providers.map((item) => {
|
||||
if (!providersData[item.provider]) return;
|
||||
existProviders++;
|
||||
});
|
||||
|
||||
return !!existProviders;
|
||||
};
|
||||
|
||||
authCallback = (profile) => {
|
||||
const { t, defaultPage } = this.props;
|
||||
const { FirstName, LastName, EMail, Serialized } = profile;
|
||||
@ -493,7 +507,7 @@ class Confirm extends React.PureComponent {
|
||||
onClick={this.onSubmit}
|
||||
/>
|
||||
</div>
|
||||
{providers && providers.length > 0 && (
|
||||
{this.oauthDataExists && (
|
||||
<Box>
|
||||
<ButtonsWrapper>{this.providerButtons()}</ButtonsWrapper>
|
||||
</Box>
|
||||
|
@ -105,6 +105,24 @@ namespace ASC.Web.Core.PublicResources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to By SMS.
|
||||
/// </summary>
|
||||
public static string ButtonSmsEnable {
|
||||
get {
|
||||
return ResourceManager.GetString("ButtonSmsEnable", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to By authenticator app.
|
||||
/// </summary>
|
||||
public static string ButtonTfaAppEnable {
|
||||
get {
|
||||
return ResourceManager.GetString("ButtonTfaAppEnable", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to A link to confirm the operation has been sent to :email (the email address of the portal owner)..
|
||||
/// </summary>
|
||||
|
@ -53,10 +53,10 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ActivateMobilePhoneEmptyCode" xml:space="preserve">
|
||||
<value>Das Feld mit dem Prüfcode darf nicht leer sein</value>
|
||||
@ -73,6 +73,12 @@
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Ihre Nachricht wurde erfolgreich gesendet. Der Portaladministrator wird Sie kontaktieren.</value>
|
||||
</data>
|
||||
<data name="ButtonSmsEnable" xml:space="preserve">
|
||||
<value>Per SMS</value>
|
||||
</data>
|
||||
<data name="ButtonTfaAppEnable" xml:space="preserve">
|
||||
<value>Über die Authentifizierungs-App</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Der Link zum Bestätigen der Operation wurde an :email verschickt (die E-Mail-Adresse des Portalbesitzers).</value>
|
||||
</data>
|
||||
|
@ -53,10 +53,10 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ActivateMobilePhoneEmptyCode" xml:space="preserve">
|
||||
<value>Campo de código de validación no puede estar vacío</value>
|
||||
@ -73,6 +73,12 @@
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Su mensaje fue enviado con éxito. El administrador del portal se pondrá en contacto con usted.</value>
|
||||
</data>
|
||||
<data name="ButtonSmsEnable" xml:space="preserve">
|
||||
<value>Por SMS</value>
|
||||
</data>
|
||||
<data name="ButtonTfaAppEnable" xml:space="preserve">
|
||||
<value>Con ayuda de la aplicación para autenticación</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Un enlace para confirmar la operación ha sido enviada al :correo electrónico (la dirección del correo electrónico del propietario del portal).</value>
|
||||
</data>
|
||||
|
@ -53,10 +53,10 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ActivateMobilePhoneEmptyCode" xml:space="preserve">
|
||||
<value>Le champ du code de validation ne peut pas être vide</value>
|
||||
@ -73,6 +73,12 @@
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Votre message a été envoyé avec succès. Vous serez contacté par l'administrateur du portail.</value>
|
||||
</data>
|
||||
<data name="ButtonSmsEnable" xml:space="preserve">
|
||||
<value>par SMS</value>
|
||||
</data>
|
||||
<data name="ButtonTfaAppEnable" xml:space="preserve">
|
||||
<value>Par l'application authentificateur</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Un lien pour confirmer l'opération a été envoyé à :e-mail (l'adresse e-mail du propriétaire du portail).</value>
|
||||
</data>
|
||||
|
@ -53,10 +53,10 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ActivateMobilePhoneEmptyCode" xml:space="preserve">
|
||||
<value>Il campo Valida codice non può essere vuoto</value>
|
||||
@ -73,6 +73,12 @@
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Il tuo messaggio è stato inviato con successo. Sarai contattato dall'amministratore del portale.</value>
|
||||
</data>
|
||||
<data name="ButtonSmsEnable" xml:space="preserve">
|
||||
<value>Tramite SMS</value>
|
||||
</data>
|
||||
<data name="ButtonTfaAppEnable" xml:space="preserve">
|
||||
<value>Con authenticator app</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Un collegamento per confermare l'operazione è stato inviato all'indirizzo :email (l'indirizzo email del proprietario del portale).</value>
|
||||
</data>
|
||||
|
@ -53,10 +53,10 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ActivateMobilePhoneEmptyCode" xml:space="preserve">
|
||||
<value>Validation code field cannot be empty</value>
|
||||
@ -73,6 +73,12 @@
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Your message was successfully sent. You will be contacted by the portal administrator.</value>
|
||||
</data>
|
||||
<data name="ButtonSmsEnable" xml:space="preserve">
|
||||
<value>By SMS</value>
|
||||
</data>
|
||||
<data name="ButtonTfaAppEnable" xml:space="preserve">
|
||||
<value>By authenticator app</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>A link to confirm the operation has been sent to :email (the email address of the portal owner).</value>
|
||||
</data>
|
||||
|
@ -53,10 +53,10 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.4.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.5.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="ActivateMobilePhoneEmptyCode" xml:space="preserve">
|
||||
<value>Поле кода подтверждения не может быть пустым</value>
|
||||
@ -73,6 +73,12 @@
|
||||
<data name="AdminMessageSent" xml:space="preserve">
|
||||
<value>Ваше сообщение успешно отправлено. Администратор портала с Вами свяжется.</value>
|
||||
</data>
|
||||
<data name="ButtonSmsEnable" xml:space="preserve">
|
||||
<value>С помощью SMS</value>
|
||||
</data>
|
||||
<data name="ButtonTfaAppEnable" xml:space="preserve">
|
||||
<value>С помощью приложения для аутентификации</value>
|
||||
</data>
|
||||
<data name="ChangePortalOwnerMsg" xml:space="preserve">
|
||||
<value>Ссылка для подтверждения операции была отправлена на :email (адрес электронной почты владельца портала).</value>
|
||||
</data>
|
||||
|
@ -362,10 +362,12 @@ const Form = (props) => {
|
||||
const providerButtons =
|
||||
providers &&
|
||||
providers.map((item, index) => {
|
||||
if (!providersData[item.provider]) return;
|
||||
|
||||
const { icon, label, iconOptions, className } = providersData[
|
||||
item.provider
|
||||
];
|
||||
if (!icon) return;
|
||||
|
||||
if (item.provider === "Facebook") {
|
||||
facebookIndex = index;
|
||||
return;
|
||||
@ -390,6 +392,17 @@ const Form = (props) => {
|
||||
return providerButtons;
|
||||
};
|
||||
|
||||
const oauthDataExists = () => {
|
||||
let existProviders = 0;
|
||||
providers && providers.length > 0;
|
||||
providers.map((item) => {
|
||||
if (!providersData[item.provider]) return;
|
||||
existProviders++;
|
||||
});
|
||||
|
||||
return !!existProviders;
|
||||
};
|
||||
|
||||
//console.log("Login render");
|
||||
|
||||
return (
|
||||
@ -507,7 +520,7 @@ const Form = (props) => {
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{providers && providers.length > 0 && (
|
||||
{oauthDataExists() && (
|
||||
<>
|
||||
<Box displayProp="flex" alignItems="center" marginProp="0 0 16px 0">
|
||||
<div className="login-bottom-border"></div>
|
||||
|
Loading…
Reference in New Issue
Block a user