Merge branch 'release/v1.2' of github.com:ONLYOFFICE/AppServer into release/v1.2

This commit is contained in:
Vlada Gazizova 2022-04-29 12:34:37 +03:00
commit 26b84622cf
56 changed files with 562 additions and 317 deletions

View File

@ -1,3 +1,5 @@
@echo off
echo "##########################################################"
echo "######### Start build and deploy Personal ##############"
echo "##########################################################"
@ -6,6 +8,7 @@ echo.
PUSHD %~dp0
call runasadmin.bat "%~dpnx0"
if %errorlevel% == 0 (
call start\stop.bat nopause
@ -18,7 +21,11 @@ call build\build.static.bat nopause personal
echo "BACK-END"
call build\build.backend.bat nopause
start /b call build\start\start.bat nopause
PUSHD %~dp0
call start\start.bat nopause
echo.
pause
)

View File

@ -74,4 +74,6 @@ sed -i "s!\"Threads\".*!\"Threads\": \"${ELK_THREADS}\"!g" ${PATH_TO_CONF}/elast
sed -i "s!\"subfolder\".*!\"subfolder\": \"server\",!g" ${PATH_TO_CONF}/appsettings.services.json
sed -i "s!\"BootstrapServers\".*!\"BootstrapServers\": \"${KAFKA_HOST}\"!g" ${PATH_TO_CONF}/kafka.${APP_DOTNET_ENV}.json
sed -i "s!\"path\".*!\"path\": \"../../ASC.Socket.IO\"!g" ${PATH_TO_CONF}/socket.${APP_DOTNET_ENV}.json
dotnet ${DOTNET_RUN} --urls=${URLS} --ENVIRONMENT=${APP_DOTNET_ENV} --'$STORAGE_ROOT'=${APP_STORAGE_ROOT} --pathToConf=${PATH_TO_CONF} --log:dir=${LOG_DIR} --log:name=${DOTNET_LOG_NAME} ${PARAMETERS}

View File

@ -14,7 +14,7 @@
],
"scripts": {
"build": "lerna run build --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc",
"build:personal": "lerna run build --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor}",
"build:personal": "lerna run build:personal --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor}",
"build:test": "lerna run build:test --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info",
"build:test.translation": "lerna run build:test.translation --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc --ignore @appserver/debug-info",
"bump": "lerna version --no-push --no-git-tag-version",
@ -23,7 +23,7 @@
"deploy:personal": "shx rm -rf build/deploy/products && shx rm -rf build/deploy/public && shx rm -rf build/deploy/studio && lerna run deploy --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor} && shx cp -r public build/deploy",
"serve": "lerna run serve --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc",
"start": "lerna run start --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc",
"start:personal": "lerna run start --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor}",
"start:personal": "lerna run start:personal --parallel --scope {@appserver/studio,@appserver/people,@appserver/files,@appserver/editor}",
"start-prod": "lerna run start-prod --parallel --ignore @appserver/common --ignore @appserver/components --ignore @appserver/browserslist-config-asc",
"storybook": "yarn workspace @appserver/components storybook",
"storybook-build": "yarn workspace @appserver/components run storybook-build",

View File

@ -229,6 +229,7 @@ class Section extends React.Component {
snackbarExist,
showText,
infoPanelIsVisible,
isInfoPanelAvailable,
} = this.props;
let sectionHeaderContent = null;
@ -467,12 +468,16 @@ class Section extends React.Component {
<></>
)}
</SectionContainer>
<InfoPanel>
<SubInfoPanelHeader>
{infoPanelHeaderContent}
</SubInfoPanelHeader>
<SubInfoPanelBody>{infoPanelBodyContent}</SubInfoPanelBody>
</InfoPanel>
{isInfoPanelAvailable && (
<InfoPanel>
<SubInfoPanelHeader>
{infoPanelHeaderContent}
</SubInfoPanelHeader>
<SubInfoPanelBody>
{infoPanelBodyContent}
</SubInfoPanelBody>
</InfoPanel>
)}
</Provider>
)}
</ReactResizeDetector>
@ -539,11 +544,13 @@ Section.propTypes = {
isHeaderVisible: PropTypes.bool,
firstLoad: PropTypes.bool,
isHomepage: PropTypes.bool,
isInfoPanelAvailable: PropTypes.bool,
};
Section.defaultProps = {
withBodyScroll: true,
withBodyAutoFocus: false,
isInfoPanelAvailable: true,
};
Section.InfoPanelHeader = InfoPanelHeader;

View File

@ -15,6 +15,7 @@ import { isMobile } from "react-device-detect";
const StyledInfoPanelWrapper = styled.div.attrs(({ id }) => ({
id: id,
}))`
user-select: none;
height: auto;
width: auto;
background: rgba(6, 22, 38, 0.2);

View File

@ -343,3 +343,7 @@ export function getFolderOptions(folderId, filter) {
return options;
}
export function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}

View File

@ -96,6 +96,20 @@ class AvatarEditor extends React.Component {
}
}
keyPress = (e) => {
if (e.keyCode === 13) {
this.onSaveButtonClick();
}
};
componentDidMount() {
addEventListener("keydown", this.keyPress, false);
}
componentWillUnmount() {
removeEventListener("keydown", this.keyPress, false);
}
render() {
const {
displayType,

View File

@ -29,6 +29,8 @@ class FieldContainer extends React.Component {
errorMessage,
errorColor,
errorMessageWidth,
offsetRight,
tooltipMaxWidth,
} = this.props;
return (
@ -53,7 +55,9 @@ class FieldContainer extends React.Component {
<HelpButton
tooltipContent={tooltipContent}
place={place}
offsetRight={offsetRight}
helpButtonHeaderContent={helpButtonHeaderContent}
tooltipMaxWidth={tooltipMaxWidth}
/>
)}
</div>
@ -109,6 +113,8 @@ FieldContainer.propTypes = {
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
offsetRight: PropTypes.number,
tooltipMaxWidth: PropTypes.string,
};
FieldContainer.defaultProps = {
@ -116,6 +122,7 @@ FieldContainer.defaultProps = {
labelVisible: true,
maxLabelWidth: "110px",
errorMessageWidth: "293px",
offsetRight: 0,
};
export default FieldContainer;

View File

@ -106,6 +106,7 @@ class HelpButton extends React.Component {
offsetLeft={offsetLeft}
afterShow={this.afterShow}
afterHide={this.afterHide}
maxWidth={tooltipMaxWidth}
>
{tooltipContent}
</Tooltip>

View File

@ -84,7 +84,8 @@ const StyledLinkWithDropdown = styled(SimpleLinkWithDropdown)`
text-decoration: none;
user-select: none;
position: relative;
display: inline-grid;
display: flex;
align-items: center;
padding-right: ${(props) => props.theme.linkWithDropdown.paddingRight};

View File

@ -39,7 +39,7 @@ export class CustomScrollbars extends React.Component {
}
CustomScrollbars.defaultProps = {
stype: "smallBlack",
stype: "mediumBlack",
};
const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => (

View File

@ -114,7 +114,7 @@ Scrollbar.propTypes = {
};
Scrollbar.defaultProps = {
stype: "smallBlack",
stype: "mediumBlack",
};
export default Scrollbar;

View File

@ -40,12 +40,17 @@ const StyledTableContainer = styled.div`
border-image-source: ${(props) =>
props.theme.tableContainer.header.borderImageSource};
border-top: 0;
}
.lengthen-header {
border-bottom: ${(props) =>
props.theme.tableContainer.header.borderBottom};
border-image-source: none;
}
.lengthen-header {
border-bottom: ${(props) => props.theme.tableContainer.header.borderBottom};
border-image-source: none;
}
.hotkeys-lengthen-header {
border-bottom: ${(props) =>
props.theme.tableContainer.header.hotkeyBorderBottom};
border-image-source: none;
}
.content-container {

View File

@ -580,7 +580,7 @@ const Base = {
modalBorderRadius: "6px",
asidePadding: "0 16px 16px",
heading: {
maxWidth: "500px",
maxWidth: "calc(100% - 18px)",
margin: "0",
modalLineHeight: "40px",
asideLineHeight: "56px",
@ -2078,6 +2078,7 @@ const Base = {
hoverIconColor: grayMain,
borderImageSource: `linear-gradient(to right,${white} 21px,${grayLightMid} 21px,${grayLightMid} calc(100% - 20px),${white} calc(100% - 20px))`,
hotkeyBorderBottom: `1px solid ${globalColors.blueMain}`,
},
tableCell: {

View File

@ -579,7 +579,7 @@ const Dark = {
asidePadding: "0 16px 16px",
heading: {
maxWidth: "500px",
maxWidth: "calc(100% - 18px)",
margin: "0",
fontWeight: "700",
modalLineHeight: "40px",
@ -2081,6 +2081,7 @@ const Dark = {
hoverIconColor: grayMaxLight,
borderImageSource: `linear-gradient(to right,${black} 21px,#474747 21px,#474747 calc(100% - 20px),${black} calc(100% - 20px))`,
hotkeyBorderBottom: `1px solid ${globalColors.blueMain}`,
},
tableCell: {

View File

@ -5,12 +5,14 @@
"homepage": "/products/files",
"scripts": {
"build": "webpack --mode production",
"build:personal": "webpack --mode production --env personal=true",
"build:test": "webpack --env minimize=false --mode production",
"build:test.translation": "webpack --env minimize=false hideText=true --mode production",
"clean": "shx rm -rf dist",
"deploy": "shx --silent mkdir -p ../../../build/deploy/products/ASC.Files/client && shx cp -r dist/* ../../../build/deploy/products/ASC.Files/client",
"serve": "serve dist -p 5008",
"start": "webpack-cli serve",
"start:personal": "webpack-cli serve --env personal=true",
"start-prod": "webpack --mode production && serve dist -p 5008",
"test:codeceptjs": "npx codeceptjs run --reporter mocha-multi",
"test:mobile": "cross-env DEVICE_TYPE=mobile yarn test:codeceptjs",

View File

@ -121,7 +121,7 @@ export default function withFileActions(WrappedFileItem) {
};
onFilesClick = (e) => {
const { item, openFileAction } = this.props;
const { item, openFileAction, setParentId } = this.props;
if (
(e && e.target.tagName === "INPUT") ||
!!e.target.closest(".lock-file")
@ -129,6 +129,16 @@ export default function withFileActions(WrappedFileItem) {
return;
e.preventDefault();
if (
item.isFolder &&
item.parentId !== 0 &&
item.filesCount === 0 &&
item.foldersCount === 0
) {
setParentId(item.parentId);
}
openFileAction(item);
};
@ -222,7 +232,7 @@ export default function withFileActions(WrappedFileItem) {
filesActionsStore,
dialogsStore,
treeFoldersStore,
//selectedFolderStore,
selectedFolderStore,
filesStore,
uploadDataStore,
settingsStore,
@ -313,6 +323,7 @@ export default function withFileActions(WrappedFileItem) {
actionId: id,
checked: isFileSelected(item.id, item.parentId),
//parentFolder: selectedFolderStore.parentId,
setParentId: selectedFolderStore.setParentId,
canWebEdit,
canViewedDocs,
isTrashFolder: isRecycleBinFolder,

View File

@ -49,6 +49,8 @@ const withHotkeys = (Component) => {
filterPreventDefault: false,
enableOnTags: ["INPUT"],
enabled: !someDialogIsOpen && enabledHotkeys && !mediaViewerIsVisible,
keyup: true,
keydown: false,
};
const onKeyDown = (e) => activateHotkeys(e);

View File

@ -65,7 +65,7 @@ const ArticleBodyContent = (props) => {
if (!filesSection) {
const filter = FilesFilter.getDefault();
filter.folder = data[0];
filter.folder = data;
const urlFilter = filter.toUrlParams();

View File

@ -104,7 +104,7 @@ const Badges = ({
const lineHeightBadge = isTile || tabletViewBadge ? "1.46" : "1.34";
const paddingBadge = isTile || tabletViewBadge ? "0 5px" : "0 3px";
const paddingBadge = "0 5px";
const fontSizeBadge = isTile || tabletViewBadge ? "11px" : "9px";

View File

@ -23,7 +23,7 @@ const FolderTreeBody = ({
{isAvailable ? (
<StyledTree theme={theme}>
<div className="selection-panel_tree-folder">
<Scrollbar id="folder-tree-scroll-bar">
<Scrollbar id="folder-tree-scroll-bar" stype="mediumBlack">
<TreeFolders
isPanel={true}
expandedPanelKeys={expandedKeys}

View File

@ -6,12 +6,20 @@ import RowContainer from "@appserver/components/row-container";
import Text from "@appserver/components/text";
import LinkWithDropdown from "@appserver/components/link-with-dropdown";
import styled from "styled-components";
import { tablet } from "@appserver/components/utils/device";
const StyledDownloadContent = styled.div`
.row_content,
.row-content_tablet-side-info {
overflow: unset;
}
@media (${tablet}) {
.row-content_tablet-side-info {
display: flex;
gap: 5px;
}
}
`;
const DownloadContent = (props) => {

View File

@ -1,4 +1,5 @@
import React from "react";
import React, { useEffect } from "react";
import styled from "styled-components";
import { withRouter } from "react-router";
import ModalDialogContainer from "../ModalDialogContainer";
import Text from "@appserver/components/text";
@ -7,6 +8,10 @@ import ModalDialog from "@appserver/components/modal-dialog";
import { withTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
const StyledModal = styled(ModalDialogContainer)`
max-width: 400px;
`;
const EmptyTrashDialogComponent = (props) => {
const {
visible,
@ -17,6 +22,12 @@ const EmptyTrashDialogComponent = (props) => {
emptyTrash,
} = props;
useEffect(() => {
window.addEventListener("keydown", onKeyPress);
return () => window.removeEventListener("keydown", onKeyPress);
}, []);
const onClose = () => setEmptyTrashDialogVisible(false);
const onEmptyTrash = () => {
@ -28,12 +39,14 @@ const EmptyTrashDialogComponent = (props) => {
emptyTrash(translations);
};
const onKeyPress = (e) => {
if (e.keyCode === 13) {
onEmptyTrash();
}
};
return (
<ModalDialogContainer
isLoading={!tReady}
visible={visible}
onClose={onClose}
>
<StyledModal isLoading={!tReady} visible={visible} onClose={onClose}>
<ModalDialog.Header>{t("DeleteForeverTitle")}</ModalDialog.Header>
<ModalDialog.Body>
<Text>{t("DeleteForeverNote")}</Text>
@ -56,7 +69,7 @@ const EmptyTrashDialogComponent = (props) => {
isLoading={isLoading}
/>
</ModalDialog.Footer>
</ModalDialogContainer>
</StyledModal>
);
};

View File

@ -101,7 +101,6 @@ const Body = ({
const listRef = React.useRef();
const onToggleExternalLinkOpen = React.useCallback(() => {
setExternalLinkOpen((oldState) => !oldState);
onToggleLink && onToggleLink(externalItem);
}, [externalItem, onToggleLink]);
@ -109,6 +108,7 @@ const Body = ({
setExternalLinkVisible(
selection?.length === 1 && !!externalItem?.sharedTo?.shareLink
);
setExternalLinkOpen(externalItem?.access !== ShareAccessRights.DenyAccess);
}, [externalItem, selection]);

View File

@ -37,8 +37,7 @@ const StyledHeaderContent = styled.div`
align-items: center;
justify-content: start;
width: calc(100% - 33px);
max-width: calc(100% - 33px);
width: 100%;
.sharing_panel-arrow {
.icon-button_svg {
@ -341,10 +340,29 @@ const StyledModalFooter = styled.div`
align-items: center;
justify-content: space-between;
div:first-child {
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 0;
}
button {
width: 100%;
height: 40px;
box-sizing: border-box;
.button-content {
display: flex;
align-items: center;
justify-content: center;
}
}
button:first-child {

View File

@ -3,7 +3,7 @@ import Backdrop from "@appserver/components/backdrop";
import Button from "@appserver/components/button";
import Aside from "@appserver/components/aside";
import SaveCancelButton from "@appserver/components/save-cancel-buttons";
import { withTranslation, Trans } from "react-i18next";
import toastr from "studio/toastr";
import { ShareAccessRights } from "@appserver/common/constants";
@ -624,18 +624,12 @@ class SharingPanelComponent extends React.Component {
{!showEmbeddingContent && (
<ModalDialog.Footer>
<StyledModalFooter>
<Button
size={"normal"}
label={t("Common:SaveButton")}
primary
onClick={this.onSaveClick}
scale
/>
<Button
size={"normal"}
label={t("Common:CancelButton")}
scale
onClick={this.onClose}
<SaveCancelButton
saveButtonLabel={t("Common:SaveButton")}
onSaveClick={this.onSaveClick}
cancelButtonLabel={t("Common:CancelButton")}
onCancelClick={this.onClose}
showReminder={true}
/>
</StyledModalFooter>
</ModalDialog.Footer>
@ -692,18 +686,12 @@ class SharingPanelComponent extends React.Component {
{!showEmbeddingContent && (
<ModalDialog.Footer>
<StyledModalFooter>
<Button
size={"normal"}
label={t("Common:SaveButton")}
primary
onClick={this.onSaveClick}
scale
/>
<Button
size={"normal"}
label={t("Common:CancelButton")}
scale
onClick={this.onClose}
<SaveCancelButton
saveButtonLabel={t("Common:SaveButton")}
onSaveClick={this.onSaveClick}
cancelButtonLabel={t("Common:CancelButton")}
onCancelClick={this.onClose}
showReminder={true}
/>
</StyledModalFooter>
</ModalDialog.Footer>
@ -870,7 +858,11 @@ const SharingPanel = inject(
} = uploadDataStore;
const isShared =
selection.length > 0 && selection[0].shared ? selection[0].shared : false;
selection.length > 0 && selection[0].shared
? selection[0].shared
: bufferSelection?.shared
? bufferSelection.shared
: false;
return {
theme: auth.settingsStore.theme,

View File

@ -70,9 +70,9 @@ const StyledFileTileTop = styled.div`
.thumbnail-image {
pointer-events: none;
position: relative;
height: 100%;
/* height: 100%;
width: 100%;
object-fit: cover;
object-fit: cover; */
border-radius: 6px 6px 0 0;
z-index: 0;
}

View File

@ -42,8 +42,9 @@ class Tile extends React.PureComponent {
getIconFile = () => {
const { thumbnailClick, item } = this.props;
const src =
item.attributes.template_image.data.attributes.formats.small.url;
// const src =
// item.attributes.template_image.data.attributes.formats.small.url;
const src = item.attributes.card_prewiew.data.attributes.url;
const svgLoader = () => <div style={{ width: "96px" }} />;
return src ? (

View File

@ -1,5 +1,6 @@
import { FileType } from "@appserver/common/constants";
import { LANGUAGE } from "@appserver/common/constants";
import { sleep } from "@appserver/common/utils";
import Link from "@appserver/components/link";
import Text from "@appserver/components/text";
import Tooltip from "@appserver/components/tooltip";
@ -30,6 +31,9 @@ const SingleItem = (props) => {
dontShowSize,
dontShowLocation,
dontShowAccess,
personal,
createThumbnail,
getFileInfo,
} = props;
let updateSubscription = true;
@ -197,46 +201,70 @@ const SingleItem = (props) => {
const loadAsyncData = async (displayedItem, selectedItem) => {
if (!updateSubscription) return;
const updateLoadedItemProperties = async (displayedItem, selectedItem) => {
const parentFolderId = selectedItem.isFolder
? selectedItem.parentId
: selectedItem.folderId;
if (
!selectedItem.thumbnailUrl &&
!selectedItem.isFolder &&
selectedItem.thumbnailStatus === 0 &&
(selectedItem.fileType === FileType.Image ||
selectedItem.fileType === FileType.Spreadsheet ||
selectedItem.fileType === FileType.Presentation ||
selectedItem.fileType === FileType.Document)
) {
await createThumbnail(selectedItem.id);
const noLocationProperties = [...displayedItem.properties].filter(
(dip) => dip.id !== "Location"
);
await sleep(5000);
let result;
await getFolderInfo(parentFolderId)
.catch(() => {
result = noLocationProperties;
})
.then((data) => {
if (!data) {
result = noLocationProperties;
return;
}
result = [...displayedItem.properties].map((dip) =>
dip.id === "Location"
? {
id: "Location",
title: t("Location"),
content: (
<Link
className="property-content"
href={`/products/files/filter?folder=${parentFolderId}`}
isHovered={true}
>
{data.title}
</Link>
),
}
: dip
);
const newFileInfo = await getFileInfo(selectedItem.id);
if (newFileInfo.thumbnailUrl) {
displayedItem.thumbnailUrl = newFileInfo.thumbnailUrl;
setItem({
...displayedItem,
});
}
}
return result;
};
// const updateLoadedItemProperties = async (displayedItem, selectedItem) => {
// const parentFolderId = selectedItem.isFolder
// ? selectedItem.parentId
// : selectedItem.folderId;
// const noLocationProperties = [...displayedItem.properties].filter(
// (dip) => dip.id !== "Location"
// );
// let result;
// await getFolderInfo(parentFolderId)
// .catch(() => {
// result = noLocationProperties;
// })
// .then((data) => {
// if (!data) {
// result = noLocationProperties;
// return;
// }
// result = [...displayedItem.properties].map((dip) =>
// dip.id === "Location"
// ? {
// id: "Location",
// title: t("Location"),
// content: (
// <Link
// className="property-content"
// href={`/products/files/filter?folder=${parentFolderId}`}
// isHovered={true}
// >
// {data.title}
// </Link>
// ),
// }
// : dip
// );
// });
// return result;
// };
const updateLoadedItemAccess = async (selectedItem) => {
const accesses = await getShareUsers(
@ -282,12 +310,14 @@ const SingleItem = (props) => {
return;
}
const access = await updateLoadedItemAccess(selectedItem);
setItem({
...displayedItem,
// properties: properties,
access: access,
});
if (!personal) {
const access = await updateLoadedItemAccess(selectedItem);
setItem({
...displayedItem,
// properties: properties,
access: access,
});
}
};
const openSharingPanel = () => {
@ -309,7 +339,7 @@ const SingleItem = (props) => {
<Text className="text">{item.title}</Text>
</StyledTitle>
{selectedItem.thumbnailUrl ? (
{item.thumbnailUrl ? (
<StyledThumbnail>
<img src={item.thumbnailUrl} alt="" />
</StyledThumbnail>
@ -338,7 +368,7 @@ const SingleItem = (props) => {
})}
</StyledProperties>
{!dontShowAccess && item.access && (
{!dontShowAccess && item.access && !personal && (
<>
<StyledSubtitle>
<Text fontWeight="600" fontSize="14px">

View File

@ -24,6 +24,9 @@ const InfoPanelBodyContent = ({
isFavoritesFolder,
isGallery,
gallerySelected,
personal,
createThumbnail,
getFileInfo,
}) => {
const singleItem = (item) => {
const dontShowLocation = item.isFolder && item.parentId === 0;
@ -47,12 +50,13 @@ const InfoPanelBodyContent = ({
dontShowLocation={dontShowLocation}
dontShowSize={dontShowSize}
dontShowAccess={dontShowAccess}
personal={personal}
createThumbnail={createThumbnail}
getFileInfo={getFileInfo}
/>
);
};
console.log(selectedItems);
return isGallery ? (
!gallerySelected ? (
<GalleryEmptyScreen />
@ -83,6 +87,7 @@ InfoPanelBodyContent.defaultProps = { theme: Base };
export default inject(
({
auth,
filesStore,
settingsStore,
filesActionsStore,
@ -90,12 +95,16 @@ export default inject(
treeFoldersStore,
selectedFolderStore,
}) => {
const { personal } = auth.settingsStore;
const {
selection,
bufferSelection,
getFolderInfo,
getShareUsers,
gallerySelected,
createThumbnail,
getFileInfo,
} = filesStore;
const { getIcon, getFolderIcon } = settingsStore;
const { onSelectItem } = filesActionsStore;
@ -126,6 +135,9 @@ export default inject(
isRecentFolder,
isFavoritesFolder,
gallerySelected,
personal,
createThumbnail,
getFileInfo,
};
}
)(

View File

@ -12,6 +12,7 @@ import withQuickButtons from "../../../../../HOCs/withQuickButtons";
import ItemIcon from "../../../../../components/ItemIcon";
import marginStyles from "./CommonStyles";
import { Base } from "@appserver/components/themes";
import { tablet } from "@appserver/components/utils/device";
const checkedStyle = css`
background: ${(props) => props.theme.filesSection.rowView.checkedBackground};
@ -72,6 +73,13 @@ const StyledSimpleFilesRow = styled(Row)`
padding-right: 24px;
margin-left: -24px;
margin-right: -24px;
@media ${tablet} {
margin-left: -16px;
margin-right: -16px;
padding-left: 16px;
padding-right: 16px;
}
`}
}
@ -98,8 +106,7 @@ const StyledSimpleFilesRow = styled(Row)`
.row_content {
${(props) =>
props.sectionWidth > 500 &&
`max-width: fit-content;`}//min-width: auto;;;;;;;
props.sectionWidth > 500 && `max-width: fit-content;`}//min-width: auto
}
.badges {

View File

@ -32,10 +32,6 @@ const StyledTableContainer = styled(TableContainer)`
.table-row {
.table-container_file-name-cell,
.table-container_row-context-menu-wrapper {
margin-top: -1px;
border-top: ${(props) =>
`1px ${props.theme.filesSection.tableView.row.borderColor} solid`};
border-bottom: ${(props) =>
`1px solid ${props.theme.filesSection.tableView.row.borderColor}`};
}

View File

@ -107,22 +107,26 @@ class FilesTableHeader extends React.Component {
}
onBeginScroll = () => {
const { firstElemChecked, headerBorder } = this.props;
const { firstElemChecked } = this.props;
const currentScrollPosition = this.customScrollElm.scrollTop;
const elem = document.getElementById("table-container_caption-header");
if (elem && headerBorder) elem.style.borderColor = "#2da7db";
if (currentScrollPosition === 0) {
this.isBeginScrolling = false;
this.props.firstElemChecked &&
this.props.headerBorder &&
elem?.classList?.add("hotkeys-lengthen-header");
!firstElemChecked && elem?.classList?.remove("lengthen-header");
return;
}
if (elem) elem.style.borderColor = "#ECEEF1";
!this.isBeginScrolling && elem?.classList?.add("lengthen-header");
if (!this.isBeginScrolling) {
elem?.classList?.remove("hotkeys-lengthen-header");
elem?.classList?.add("lengthen-header");
}
this.isBeginScrolling = true;
};
@ -138,7 +142,7 @@ class FilesTableHeader extends React.Component {
if (this.props.firstElemChecked && this.props.headerBorder) {
const elem = document.getElementById("table-container_caption-header");
if (elem) elem.style.borderColor = "#2da7db";
elem?.classList?.add("hotkeys-lengthen-header");
}
}

View File

@ -154,7 +154,7 @@ const StyledBadgesContainer = styled.div`
.badge-version {
width: max-content;
margin: -2px 6px -2px -2px;
margin: 0 6px -2px -2px;
}
.badge-new-version {
@ -265,7 +265,7 @@ const FilesTableRow = (props) => {
React.useEffect(() => {
if (index === 0) {
if (checkedProps || isActive) {
if (checkedProps || isActive || showHotkeyBorder) {
setFirsElemChecked(true);
} else {
setFirsElemChecked(false);
@ -273,8 +273,6 @@ const FilesTableRow = (props) => {
if (showHotkeyBorder) {
setHeaderBorder(true);
} else {
const elem = document.getElementById("table-container_caption-header");
if (elem) elem.style.borderColor = "#ECEEF1";
setHeaderBorder(false);
}
}

View File

@ -46,7 +46,7 @@ const PureSettings = ({
}, [title, t]);
return (
<Section>
<Section isInfoPanelAvailable={false}>
<Section.SectionHeader>
{(!isLoadedSettingsTree && isLoading) || isLoading || !tReady ? (
<Loaders.SectionHeader />

View File

@ -1955,6 +1955,12 @@ class FilesStore {
if (fileIds.length) return api.files.createThumbnails(fileIds);
};
createThumbnail = async (fileId) => {
if (!fileId) return;
await api.files.createThumbnails([fileId]);
};
setIsUpdatingRowItem = (updating) => {
this.isUpdatingRowItem = updating;
};

View File

@ -79,7 +79,9 @@ class HotkeyStore {
) {
//console.log("element is visible");
} else {
if (scroll) scroll.style.overflowX = "hidden"; //hack to fix react-custom-scrollbar bug with horizontal scroll
el.scrollIntoView({ block: "center" });
if (scroll) scroll.style.overflowX = null;
//console.log("element is not visible");
}
}

View File

@ -52,6 +52,10 @@ class SelectedFolderStore {
this.providerItem = null;
};
setParentId = (parentId) => {
this.parentId = parentId;
};
setSelectedFolder = (selectedFolder) => {
const { socketHelper } = this.settingsStore;

View File

@ -5,6 +5,8 @@ const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const ExternalTemplateRemotesPlugin = require("external-remotes-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const DefinePlugin = require("webpack").DefinePlugin;
const combineUrl = require("@appserver/common/utils/combineUrl");
const AppServerConfig = require("@appserver/common/constants/AppServerConfig");
const sharedDeps = require("@appserver/common/constants/sharedDependencies");
@ -249,5 +251,11 @@ module.exports = (env, argv) => {
config.devtool = "cheap-module-source-map";
}
config.plugins.push(
new DefinePlugin({
IS_PERSONAL: env.personal || false,
})
);
return config;
};

View File

@ -5,12 +5,14 @@
"homepage": "/products/people",
"scripts": {
"build": "webpack --mode production",
"build:personal": "webpack --mode production --env personal=true",
"build:test": "webpack --env minimize=false --mode production",
"build:test.translation": "webpack --env minimize=false hideText=true --mode production",
"clean": "shx rm -rf dist",
"deploy": "shx --silent mkdir -p ../../../build/deploy/products/ASC.People/client && shx cp -r dist/* ../../../build/deploy/products/ASC.People/client",
"serve": "serve dist -p 5002",
"start": "webpack-cli serve",
"start:personal": "webpack-cli serve --env personal=true",
"start-prod": "webpack --mode production && serve dist -p 5002",
"test:codeceptjs": "npx codeceptjs run --reporter mocha-multi",
"test:mobile": "cross-env DEVICE_TYPE=mobile yarn test:codeceptjs",

View File

@ -19,6 +19,7 @@ class ChangePasswordDialogComponent extends React.Component {
}
onSendPasswordChangeInstructions = () => {
const { email, onClose } = this.props;
this.setState({ isRequestRunning: true }, () => {
sendInstructionsToChangePassword(email)
.then((res) => {
@ -31,8 +32,22 @@ class ChangePasswordDialogComponent extends React.Component {
});
};
keyPress = (e) => {
if (e.keyCode === 13) {
this.onSendPasswordChangeInstructions();
}
};
componentDidMount() {
addEventListener("keydown", this.keyPress, false);
}
componentWillUnmount() {
removeEventListener("keydown", this.keyPress, false);
}
render() {
console.log("ChangePasswordDialog render");
// console.log("ChangePasswordDialog render");
const { t, tReady, visible, email, onClose, theme } = this.props;
const { isRequestRunning } = this.state;

View File

@ -93,6 +93,10 @@ const IconButtonWrapper = styled.div`
}
`;
const LangSelectorContainer = styled.div`
display: flex;
`;
class ProfileInfo extends React.PureComponent {
constructor(props) {
super(props);
@ -268,7 +272,7 @@ class ProfileInfo extends React.PureComponent {
<Link
color={theme.profileInfo.tooltipLinkColor}
isHovered={true}
href="https://helpcenter.onlyoffice.com/ru/guides/become-translator.aspx"
href={`https://helpcenter.onlyoffice.com/${language}/guides/become-translator.aspx`}
target="_blank"
>
{t("Common:LearnMore")}
@ -376,7 +380,7 @@ class ProfileInfo extends React.PureComponent {
<InfoItemLabel>{t("Common:Language")}:</InfoItemLabel>
<InfoItemValue>
{cultureNames ? (
<>
<LangSelectorContainer>
<ComboBox
directionY="both"
options={cultureNames}
@ -400,7 +404,7 @@ class ProfileInfo extends React.PureComponent {
helpButtonHeaderContent={t("Common:Language")}
className="help-icon"
/>
</>
</LangSelectorContainer>
) : (
<Loaders.Text />
)}

View File

@ -326,7 +326,7 @@ class SectionHeaderContent extends React.PureComponent {
{
key: "edit",
className: "header-context-menu_edit",
label: t("EditUser"),
label: t("Profile:EditUser"),
onClick: this.onEditClick,
},
{

View File

@ -45,6 +45,8 @@ class TextChangeField extends React.Component {
tooltipContent={tooltipContent}
helpButtonHeaderContent={helpButtonHeaderContent}
maxLabelWidth={maxLabelWidth}
offsetRight={100}
tooltipMaxWidth="300px"
>
<InputContainer>
<TextInput

View File

@ -241,6 +241,8 @@ class UpdateUserForm extends React.Component {
};
onBirthdayDateChange = (value) => {
value.setHours(0, -value.getTimezoneOffset(), 0, 0);
var stateCopy = Object.assign({}, this.state);
const birthday = value ? value.toJSON() : stateCopy.profile.workFrom;
stateCopy.profile.birthday = birthday;
@ -254,7 +256,10 @@ class UpdateUserForm extends React.Component {
};
onWorkFromDateChange = (value) => {
value.setHours(0, -value.getTimezoneOffset(), 0, 0);
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.workFrom = value ? value.toJSON() : null;
this.setState(stateCopy);
this.setIsEdit();
@ -685,7 +690,8 @@ class UpdateUserForm extends React.Component {
<Link
color="#316DAA"
isHovered={true}
href="https://helpcenter.onlyoffice.com/ru/gettingstarted/people.aspx#ManagingAccessRights_block"
href={`https://helpcenter.onlyoffice.com/${language}/gettingstarted/people.aspx#ManagingAccessRights_block`}
target="_blank"
style={{ marginTop: 23 }}
>
{t("TermsOfUsePopupHelperLink")}

View File

@ -1,29 +1,32 @@
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin;
const ExternalTemplateRemotesPlugin = require('external-remotes-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const combineUrl = require('@appserver/common/utils/combineUrl');
const AppServerConfig = require('@appserver/common/constants/AppServerConfig');
const sharedDeps = require('@appserver/common/constants/sharedDependencies');
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const ExternalTemplateRemotesPlugin = require("external-remotes-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const DefinePlugin = require("webpack").DefinePlugin;
const path = require('path');
const pkg = require('./package.json');
const combineUrl = require("@appserver/common/utils/combineUrl");
const AppServerConfig = require("@appserver/common/constants/AppServerConfig");
const sharedDeps = require("@appserver/common/constants/sharedDependencies");
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies || {};
const homepage = pkg.homepage; //combineUrl(AppServerConfig.proxyURL, pkg.homepage);
const title = pkg.title;
var config = {
mode: 'development',
entry: './src/index',
mode: "development",
entry: "./src/index",
devServer: {
devMiddleware: {
publicPath: homepage,
},
static: {
directory: path.join(__dirname, 'dist'),
directory: path.join(__dirname, "dist"),
publicPath: homepage,
},
port: 5002,
@ -35,22 +38,23 @@ var config = {
},
hot: false,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers":
"X-Requested-With, content-type, Authorization",
},
},
output: {
publicPath: 'auto',
chunkFilename: 'static/js/[id].[contenthash].js',
publicPath: "auto",
chunkFilename: "static/js/[id].[contenthash].js",
//assetModuleFilename: "static/images/[hash][ext][query]",
path: path.resolve(process.cwd(), 'dist'),
filename: 'static/js/[name].[contenthash].bundle.js',
path: path.resolve(process.cwd(), "dist"),
filename: "static/js/[name].[contenthash].bundle.js",
},
resolve: {
extensions: ['.jsx', '.js', '.json'],
extensions: [".jsx", ".js", ".json"],
fallback: {
crypto: false,
},
@ -65,14 +69,14 @@ var config = {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
type: 'asset/resource',
type: "asset/resource",
generator: {
filename: 'static/images/[hash][ext][query]',
filename: "static/images/[hash][ext][query]",
},
},
{
test: /\.m?js/,
type: 'javascript/auto',
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
@ -81,7 +85,7 @@ var config = {
test: /\.react.svg$/,
use: [
{
loader: '@svgr/webpack',
loader: "@svgr/webpack",
options: {
svgoConfig: {
plugins: [{ removeViewBox: false }],
@ -90,26 +94,26 @@ var config = {
},
],
},
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.json$/, loader: "json-loader" },
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
"style-loader",
// Translates CSS into CommonJS
{
loader: 'css-loader',
loader: "css-loader",
options: {
url: {
filter: (url, resourcePath) => {
// resourcePath - path to css file
// Don't handle `/static` urls
if (url.startsWith('/static') || url.startsWith('data:')) {
if (url.startsWith("/static") || url.startsWith("data:")) {
return false;
}
@ -119,7 +123,7 @@ var config = {
},
},
// Compiles Sass to CSS
'sass-loader',
"sass-loader",
],
},
@ -128,17 +132,17 @@ var config = {
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
loader: "babel-loader",
options: {
presets: ['@babel/preset-react', '@babel/preset-env'],
presets: ["@babel/preset-react", "@babel/preset-env"],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-export-default-from',
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-export-default-from",
],
},
},
'source-map-loader',
"source-map-loader",
],
},
],
@ -147,19 +151,25 @@ var config = {
plugins: [
new CleanWebpackPlugin(),
new ModuleFederationPlugin({
name: 'people',
filename: 'remoteEntry.js',
name: "people",
filename: "remoteEntry.js",
remotes: {
studio: `studio@${combineUrl(AppServerConfig.proxyURL, '/remoteEntry.js')}`,
people: `people@${combineUrl(AppServerConfig.proxyURL, '/products/people/remoteEntry.js')}`,
studio: `studio@${combineUrl(
AppServerConfig.proxyURL,
"/remoteEntry.js"
)}`,
people: `people@${combineUrl(
AppServerConfig.proxyURL,
"/products/people/remoteEntry.js"
)}`,
},
exposes: {
'./app': './src/People.jsx',
'./GroupSelector': './src/components/GroupSelector',
'./PeopleSelector': './src/components/PeopleSelector',
'./PeopleSelector/UserTooltip':
'./src/components/PeopleSelector/sub-components/UserTooltip.js',
'./MyProfile': './src/pages/My',
"./app": "./src/People.jsx",
"./GroupSelector": "./src/components/GroupSelector",
"./PeopleSelector": "./src/components/PeopleSelector",
"./PeopleSelector/UserTooltip":
"./src/components/PeopleSelector/sub-components/UserTooltip.js",
"./MyProfile": "./src/pages/My",
},
shared: {
...deps,
@ -170,11 +180,11 @@ var config = {
new CopyPlugin({
patterns: [
{
from: 'public',
from: "public",
globOptions: {
dot: true,
gitignore: true,
ignore: ['**/index.html'],
ignore: ["**/index.html"],
},
},
],
@ -187,7 +197,7 @@ module.exports = (env, argv) => {
config.plugins = [
...config.plugins,
new HtmlWebpackPlugin({
template: './public/index.html',
template: "./public/index.html",
publicPath: homepage,
title: title,
base: `${homepage}/`,
@ -213,24 +223,30 @@ module.exports = (env, argv) => {
config.plugins = [
...config.plugins,
new HtmlWebpackPlugin({
template: './public/index.html',
template: "./public/index.html",
publicPath: homepage,
title: title,
base: `${homepage}/`,
custom: '',
custom: "",
}),
];
}
if (argv.mode === 'production') {
config.mode = 'production';
if (argv.mode === "production") {
config.mode = "production";
config.optimization = {
splitChunks: { chunks: 'all' },
splitChunks: { chunks: "all" },
minimize: !env.minimize,
minimizer: [new TerserPlugin()],
};
} else {
config.devtool = 'cheap-module-source-map';
config.devtool = "cheap-module-source-map";
}
config.plugins.push(
new DefinePlugin({
IS_PERSONAL: env.personal || false,
})
);
return config;
};

View File

@ -5,12 +5,14 @@
"homepage": "",
"scripts": {
"build": "webpack --mode production",
"build:personal": "webpack --mode production --env personal=true",
"build:test": "webpack --env minimize=false --mode production",
"build:test.translation": "webpack --env minimize=false hideText=true --mode production",
"clean": "shx rm -rf dist",
"deploy": "shx --silent mkdir -p ../../build/deploy/studio/client && shx cp -r dist/* ../../build/deploy/studio/client",
"serve": "serve dist -p 5001",
"start": "webpack-cli serve",
"start:personal": "webpack-cli serve --env personal=true",
"start-prod": "webpack --mode production && serve dist -p 5001",
"test:codeceptjs": "npx codeceptjs run --reporter mocha-multi",
"test:mobile": "cross-env DEVICE_TYPE=mobile yarn test:codeceptjs",

View File

@ -61,9 +61,10 @@ const About = React.lazy(() => import("./components/pages/About"));
const Wizard = React.lazy(() => import("./components/pages/Wizard"));
const Settings = React.lazy(() => import("./components/pages/Settings"));
const ComingSoon = React.lazy(() => import("./components/pages/ComingSoon"));
const Confirm = React.lazy(() => import("./components/pages/Confirm"));
const Confirm =
!IS_PERSONAL && React.lazy(() => import("./components/pages/Confirm"));
const MyProfile = React.lazy(() => import("people/MyProfile"));
const EnterCode = React.lazy(() => import("login/codeLogin"));
const EnterCode = !IS_PERSONAL && React.lazy(() => import("login/codeLogin"));
const InvalidError = React.lazy(() =>
import("./components/pages/Errors/Invalid")
);
@ -109,13 +110,15 @@ const HomeRoute = (props) => (
</React.Suspense>
);
const ConfirmRoute = (props) => (
<React.Suspense fallback={<AppLoader />}>
<ErrorBoundary>
<Confirm {...props} />
</ErrorBoundary>
</React.Suspense>
);
const ConfirmRoute =
!IS_PERSONAL &&
((props) => (
<React.Suspense fallback={<AppLoader />}>
<ErrorBoundary>
<Confirm {...props} />
</ErrorBoundary>
</React.Suspense>
));
const PreparationPortalRoute = (props) => (
<React.Suspense fallback={<AppLoader />}>
@ -157,13 +160,15 @@ const MyProfileRoute = (props) => (
</React.Suspense>
);
const EnterCodeRoute = (props) => (
<React.Suspense fallback={<AppLoader />}>
<ErrorBoundary>
<EnterCode {...props} />
</ErrorBoundary>
</React.Suspense>
);
const EnterCodeRoute =
!IS_PERSONAL &&
((props) => (
<React.Suspense fallback={<AppLoader />}>
<ErrorBoundary>
<EnterCode {...props} />
</ErrorBoundary>
</React.Suspense>
));
const InvalidRoute = (props) => (
<React.Suspense fallback={<AppLoader />}>
@ -469,7 +474,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
const loginRoutes = [];
if (isLoaded && !personal) {
if (isLoaded && !IS_PERSONAL) {
let module;
if (roomsMode) {
module = "./roomsLogin";
@ -495,7 +500,7 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
const roomsRoutes = [];
if (roomsMode) {
if (!IS_PERSONAL && roomsMode) {
roomsRoutes.push(
<Route path={ENTER_CODE_URL} component={EnterCodeRoute} />
);
@ -514,7 +519,9 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
<PrivateRoute path={ABOUT_URL} component={AboutRoute} />
{loginRoutes}
{roomsRoutes}
<Route path={CONFIRM_URL} component={ConfirmRoute} />
{!IS_PERSONAL && (
<Route path={CONFIRM_URL} component={ConfirmRoute} />
)}
<Route path={INVALID_URL} component={InvalidRoute} />
<PrivateRoute
path={COMING_SOON_URLS}

View File

@ -55,7 +55,9 @@ const DebugInfoDialog = (props) => {
overflowProp="auto"
heightProp={modalType === "modal" ? "300px" : "70vh"}
>
<Scrollbar>{md && <ReactMarkdown children={md} />}</Scrollbar>
<Scrollbar stype="mediumBlack">
{md && <ReactMarkdown children={md} />}
</Scrollbar>
</Box>
</ModalDialog.Body>
</ModalDialog>

View File

@ -473,7 +473,7 @@ class LanguageAndTimeZone extends React.Component {
</div>
)}
{(isMobileOnly && isSmallTablet()) || isSmallTablet() ? (
<StyledScrollbar stype="smallBlack">{settingsBlock}</StyledScrollbar>
<StyledScrollbar stype="mediumBlack">{settingsBlock}</StyledScrollbar>
) : (
<> {settingsBlock}</>
)}

View File

@ -264,7 +264,7 @@ const PortalRenaming = (props) => {
</div>
)}
{(isMobileOnly && isSmallTablet()) || isSmallTablet() ? (
<StyledScrollbar stype="smallBlack">{settingsBlock}</StyledScrollbar>
<StyledScrollbar stype="mediumBlack">{settingsBlock}</StyledScrollbar>
) : (
<> {settingsBlock}</>
)}

View File

@ -295,7 +295,7 @@ class WelcomePageSettings extends React.Component {
</div>
)}
{(isMobileOnly && isSmallTablet()) || isSmallTablet() ? (
<StyledScrollbar stype="smallBlack">{settingsBlock}</StyledScrollbar>
<StyledScrollbar stype="mediumBlack">{settingsBlock}</StyledScrollbar>
) : (
<> {settingsBlock}</>
)}

View File

@ -170,46 +170,6 @@ const config = {
plugins: [
new CleanWebpackPlugin(),
new ModuleFederationPlugin({
name: "studio",
filename: "remoteEntry.js",
remotes: {
studio: `studio@${combineUrl(
AppServerConfig.proxyURL,
"/remoteEntry.js"
)}`,
people: `people@${combineUrl(
AppServerConfig.proxyURL,
"/products/people/remoteEntry.js"
)}`,
login: `login@${combineUrl(
AppServerConfig.proxyURL,
"/login/remoteEntry.js"
)}`,
files: `files@${combineUrl(
AppServerConfig.proxyURL,
"/products/files/remoteEntry.js"
)}`,
},
exposes: {
"./shell": "./src/Shell",
"./store": "./src/store",
"./Error404": "./src/components/pages/Errors/404/",
"./Error401": "./src/components/pages/Errors/401",
"./Error403": "./src/components/pages/Errors/403",
"./Error520": "./src/components/pages/Errors/520",
"./Layout": "./src/components/Layout",
"./Layout/context": "./src/components/Layout/context.js",
"./Main": "./src/components/Main",
"./toastr": "./src/helpers/toastr",
"./PreparationPortalDialog":
"./src/components/dialogs/PreparationPortalDialog/PreparationPortalDialogWrapper.js",
},
shared: {
...deps,
...sharedDeps,
},
}),
new ExternalTemplateRemotesPlugin(),
new HtmlWebpackPlugin({
template: "./public/index.html",
@ -229,14 +189,6 @@ const config = {
},
],
}),
new DefinePlugin({
VERSION: JSON.stringify(version),
BUILD_AT: DefinePlugin.runtimeValue(function () {
const timeElapsed = Date.now();
const today = new Date(timeElapsed);
return JSON.stringify(today.toISOString().split(".")[0] + "Z");
}, true),
}),
],
};
@ -252,5 +204,62 @@ module.exports = (env, argv) => {
config.devtool = "cheap-module-source-map";
}
const remotes = {
studio: `studio@${combineUrl(AppServerConfig.proxyURL, "/remoteEntry.js")}`,
people: `people@${combineUrl(
AppServerConfig.proxyURL,
"/products/people/remoteEntry.js"
)}`,
files: `files@${combineUrl(
AppServerConfig.proxyURL,
"/products/files/remoteEntry.js"
)}`,
};
if (!env.personal) {
remotes.login = `login@${combineUrl(
AppServerConfig.proxyURL,
"/login/remoteEntry.js"
)}`;
}
config.plugins.push(
new ModuleFederationPlugin({
name: "studio",
filename: "remoteEntry.js",
remotes: remotes,
exposes: {
"./shell": "./src/Shell",
"./store": "./src/store",
"./Error404": "./src/components/pages/Errors/404/",
"./Error401": "./src/components/pages/Errors/401",
"./Error403": "./src/components/pages/Errors/403",
"./Error520": "./src/components/pages/Errors/520",
"./Layout": "./src/components/Layout",
"./Layout/context": "./src/components/Layout/context.js",
"./Main": "./src/components/Main",
"./toastr": "./src/helpers/toastr",
"./PreparationPortalDialog":
"./src/components/dialogs/PreparationPortalDialog/PreparationPortalDialogWrapper.js",
},
shared: {
...deps,
...sharedDeps,
},
})
);
const defines = {
VERSION: JSON.stringify(version),
BUILD_AT: DefinePlugin.runtimeValue(function () {
const timeElapsed = Date.now();
const today = new Date(timeElapsed);
return JSON.stringify(today.toISOString().split(".")[0] + "Z");
}, true),
IS_PERSONAL: env.personal || false,
};
config.plugins.push(new DefinePlugin(defines));
return config;
};

View File

@ -5,12 +5,14 @@
"homepage": "/products/files/doceditor",
"scripts": {
"build": "webpack --mode production",
"build:personal": "webpack --mode production --env personal=true",
"build:test": "webpack --env minimize=false --mode production",
"build:test.translation": "webpack --env minimize=false hideText=true --mode production",
"clean": "shx rm -rf dist",
"deploy": "shx --silent mkdir -p ../../build/deploy/products/ASC.Files/editor && shx cp -r dist/* ../../build/deploy/products/ASC.Files/editor",
"serve": "serve dist -p 5013",
"start": "webpack-cli serve",
"start:personal": "webpack-cli serve --env personal=true",
"start-prod": "webpack --mode production && serve dist -p 5013"
},
"devDependencies": {

View File

@ -73,11 +73,11 @@ let fileInfo;
let successAuth;
let isSharingAccess;
let user = null;
let personal;
let personal = IS_PERSONAL || null;
let config;
let url = window.location.href;
const filesUrl = url.substring(0, url.indexOf("/doceditor"));
const doc = url.indexOf("doc=") !== -1 ? url.split("doc=")[1] : null;
//const doc = url.indexOf("doc=") !== -1 ? url.split("doc=")[1] : null;
toast.configure();
@ -346,13 +346,13 @@ const Editor = () => {
if (!favicon) return;
let icon = null;
switch (documentType) {
case "text":
case text:
icon = "text.ico";
break;
case "presentation":
case presentation:
icon = "presentation.ico";
break;
case "spreadsheet":
case spreadSheet:
icon = "spreadsheet.ico";
break;
default:

View File

@ -1,32 +1,35 @@
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin;
const ExternalTemplateRemotesPlugin = require('external-remotes-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const combineUrl = require('@appserver/common/utils/combineUrl');
const AppServerConfig = require('@appserver/common/constants/AppServerConfig');
const sharedDeps = require('@appserver/common/constants/sharedDependencies');
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const ExternalTemplateRemotesPlugin = require("external-remotes-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const DefinePlugin = require("webpack").DefinePlugin;
const combineUrl = require("@appserver/common/utils/combineUrl");
const AppServerConfig = require("@appserver/common/constants/AppServerConfig");
const sharedDeps = require("@appserver/common/constants/sharedDependencies");
const { proxyURL } = AppServerConfig;
const path = require('path');
const pkg = require('./package.json');
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies || {};
const homepage = pkg.homepage; // combineUrl(AppServerConfig.proxyURL, pkg.homepage);
const title = pkg.title;
const config = {
entry: './src/index',
target: 'web',
mode: 'development',
entry: "./src/index",
target: "web",
mode: "development",
devServer: {
devMiddleware: {
publicPath: homepage,
},
static: {
directory: path.join(__dirname, 'dist'),
directory: path.join(__dirname, "dist"),
publicPath: homepage,
},
port: 5013,
@ -38,25 +41,26 @@ const config = {
},
hot: false,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization',
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers":
"X-Requested-With, content-type, Authorization",
},
},
resolve: {
extensions: ['.jsx', '.js', '.json'],
extensions: [".jsx", ".js", ".json"],
fallback: {
crypto: false,
},
},
output: {
publicPath: 'auto',
chunkFilename: 'static/js/[id].[contenthash].js',
publicPath: "auto",
chunkFilename: "static/js/[id].[contenthash].js",
//assetModuleFilename: "static/images/[hash][ext][query]",
path: path.resolve(process.cwd(), 'dist'),
filename: 'static/js/[name].[contenthash].bundle.js',
path: path.resolve(process.cwd(), "dist"),
filename: "static/js/[name].[contenthash].bundle.js",
},
performance: {
@ -68,14 +72,14 @@ const config = {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
type: 'asset/resource',
type: "asset/resource",
generator: {
filename: 'static/images/[hash][ext][query]',
filename: "static/images/[hash][ext][query]",
},
},
{
test: /\.m?js/,
type: 'javascript/auto',
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
@ -84,7 +88,7 @@ const config = {
test: /\.react.svg$/,
use: [
{
loader: '@svgr/webpack',
loader: "@svgr/webpack",
options: {
svgoConfig: {
plugins: [{ removeViewBox: false }],
@ -93,26 +97,26 @@ const config = {
},
],
},
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.json$/, loader: "json-loader" },
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
"style-loader",
// Translates CSS into CommonJS
{
loader: 'css-loader',
loader: "css-loader",
options: {
url: {
filter: (url, resourcePath) => {
// resourcePath - path to css file
// Don't handle `/static` urls
if (url.startsWith('/static') || url.startsWith('data:')) {
if (url.startsWith("/static") || url.startsWith("data:")) {
return false;
}
@ -122,7 +126,7 @@ const config = {
},
},
// Compiles Sass to CSS
'sass-loader',
"sass-loader",
],
},
@ -131,17 +135,17 @@ const config = {
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
loader: "babel-loader",
options: {
presets: ['@babel/preset-react', '@babel/preset-env'],
presets: ["@babel/preset-react", "@babel/preset-env"],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-export-default-from',
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-export-default-from",
],
},
},
'source-map-loader',
"source-map-loader",
],
},
],
@ -150,14 +154,17 @@ const config = {
plugins: [
new CleanWebpackPlugin(),
new ModuleFederationPlugin({
name: 'editor',
filename: 'remoteEntry.js',
name: "editor",
filename: "remoteEntry.js",
remotes: {
studio: `studio@${combineUrl(proxyURL, '/remoteEntry.js')}`,
files: `files@${combineUrl(proxyURL, '/products/files/remoteEntry.js')}`,
studio: `studio@${combineUrl(proxyURL, "/remoteEntry.js")}`,
files: `files@${combineUrl(
proxyURL,
"/products/files/remoteEntry.js"
)}`,
},
exposes: {
'./app': './src/Editor.jsx',
"./app": "./src/Editor.jsx",
},
shared: {
...deps,
@ -166,7 +173,7 @@ const config = {
}),
new ExternalTemplateRemotesPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
template: "./public/index.html",
publicPath: homepage,
title: title,
base: `${homepage}/`,
@ -174,11 +181,11 @@ const config = {
new CopyPlugin({
patterns: [
{
from: 'public',
from: "public",
globOptions: {
dot: true,
gitignore: true,
ignore: ['**/index.html'],
ignore: ["**/index.html"],
},
},
],
@ -187,16 +194,22 @@ const config = {
};
module.exports = (env, argv) => {
if (argv.mode === 'production') {
config.mode = 'production';
if (argv.mode === "production") {
config.mode = "production";
config.optimization = {
splitChunks: { chunks: 'all' },
splitChunks: { chunks: "all" },
minimize: !env.minimize,
minimizer: [new TerserPlugin()],
};
} else {
config.devtool = 'cheap-module-source-map';
config.devtool = "cheap-module-source-map";
}
config.plugins.push(
new DefinePlugin({
IS_PERSONAL: env.personal || false,
})
);
return config;
};