Merge branch 'feature/workspaces' of github.com:ONLYOFFICE/AppServer into feature/workspaces

This commit is contained in:
TatianaLopaeva 2021-03-11 10:20:25 +03:00
commit 9362f3cd2d
63 changed files with 2151 additions and 2479 deletions

View File

@ -7,6 +7,7 @@ import {
StyledAlertIcon,
StyledCircleWrap,
StyledCircle,
IconBox,
} from "./StyledFloatingButton";
import ButtonUploadIcon from "../../../../public/images/button.upload.react.svg";
@ -40,18 +41,19 @@ const FloatingButton = ({ id, className, style, ...rest }) => {
</div>
<StyledFloatingButton>
{icon == "upload" ? (
<ButtonUploadIcon />
) : icon == "file" ? (
<ButtonFileIcon />
) : icon == "trash" ? (
<ButtonTrashIcon />
) : icon == "move" ? (
<ButtonMoveIcon />
) : (
<ButtonDuplicateIcon />
)}
<IconBox>
{icon == "upload" ? (
<ButtonUploadIcon />
) : icon == "file" ? (
<ButtonFileIcon />
) : icon == "trash" ? (
<ButtonTrashIcon />
) : icon == "move" ? (
<ButtonMoveIcon />
) : (
<ButtonDuplicateIcon />
)}
</IconBox>
<StyledAlertIcon>
{alert ? <StyledButtonAlertIcon size="medium" /> : <></>}
</StyledAlertIcon>

View File

@ -55,12 +55,15 @@ const StyledFloatingButton = styled.div`
border-radius: 50%;
background: #fff;
box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.13);
line-height: 46px;
text-align: center;
margin: 3px;
position: absolute;
`;
const IconBox = styled.div`
padding-top: 12px;
`;
const StyledAlertIcon = styled.div`
position: absolute;
width: 12px;
@ -74,4 +77,5 @@ export {
StyledCircle,
StyledFloatingButton,
StyledAlertIcon,
IconBox,
};

View File

@ -33,6 +33,21 @@ module.exports = {
"../loader/*.stories.@(js|mdx)",
"../main-button/*.stories.@(js|mdx)",
"../modal-dialog/*.stories.@(js|mdx)",
"../paging/*.stories.@(js|mdx)",
"../password-input/*.stories.@(js|mdx)",
"../progress-bar/*.stories.@(js|mdx)",
"../radio-button/*.stories.@(js|mdx)",
"../radio-button-group/*.stories.@(js|mdx)",
"../request-loader/*.stories.@(js|mdx)",
"../row/*.stories.@(js|mdx)",
"../row-container/*.stories.@(js|mdx)",
"../row-content/*.stories.@(js|mdx)",
"../save-cancel-buttons/*.stories.@(js|mdx)",
"../scrollbar/*.stories.@(js|mdx)",
"../search-input/*.stories.@(js|mdx)",
"../selected-item/*.stories.@(js|mdx)",
"../selector-add-button/*.stories.@(js|mdx)",
"../social-button/*.stories.@(js|mdx)",
],
addons: [
"@storybook/addon-links",

View File

@ -1,4 +0,0 @@
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
Enzyme.configure({ adapter: new Adapter() });

View File

@ -56,18 +56,6 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-values": "^0.3.3",
"rollup": "^1.32.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-cleanup": "^3.2.1",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-copy": "^3.3.0",
"rollup-plugin-generate-package-json": "^3.2.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^2.9.0",
"rollup-plugin-replace": "^2.2.0",
"rollup-plugin-url": "^3.0.1",
"storybook-readme": "^5.0.9",
"styled-components": "^5.2.1",
"svg-inline-loader": "^0.8.2"

View File

@ -89,29 +89,37 @@ const Paging = (props) => {
};
Paging.propTypes = {
/** Label for previous button */
previousLabel: PropTypes.string,
/** Label for next button */
nextLabel: PropTypes.string,
/** Action for previous button */
previousAction: PropTypes.func,
/** Action for next button */
nextAction: PropTypes.func,
/** Set previous button disabled */
disablePrevious: PropTypes.bool,
/** Set next button disabled */
disableNext: PropTypes.bool,
disableHover: PropTypes.bool,
/** Initial value for pageItems */
selectedPageItem: PropTypes.object,
/** Initial value for countItems */
selectedCountItem: PropTypes.object,
onSelectPage: PropTypes.func,
onSelectCount: PropTypes.func,
/** Paging combo box items */
pageItems: PropTypes.array,
/** Items per page combo box items */
countItems: PropTypes.array,
/** Indicates opening direction of combo box */
openDirection: PropTypes.oneOf(["bottom", "top"]),
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
showCountItem: PropTypes.bool.isRequired,

View File

@ -1,73 +1,134 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import {
withKnobs,
text,
boolean,
select,
number,
} from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import Paging from ".";
import Section from "../../../.storybook/decorators/section";
import React, { useState, useEffect } from "react";
import Paging from "./";
storiesOf("Components|Paging", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("base", () => {
const createPageItems = (count) => {
let pageItems = [];
for (let i = 1; i <= count; i++) {
pageItems.push({
key: i,
label: i + " of " + count,
});
}
return pageItems;
};
const countItems = [
{
key: 25,
label: "25 per page",
export default {
title: "Components/Paging",
component: Paging,
parameters: {
docs: {
description: {
component: "Paging is used to navigate med content pages",
},
{
key: 50,
label: "50 per page",
},
{
key: 100,
label: "100 per page",
},
];
},
},
argTypes: {
onSelectPage: { action: "onSelectPage" },
onSelectCount: { action: "onSelectCount" },
previousAction: { action: "onPrevious" },
nextAction: { action: "onNext" },
selectedCount: {
control: { type: "select", options: [25, 50, 100] },
description: "Property for story",
},
pageCount: { description: "Property for story" },
displayItems: { description: "Property for story" },
displayCount: { description: "Property for story" },
},
};
const displayItems = boolean("Display pageItems", true);
const displayCount = boolean("Display countItems", true);
const selectedCount = select("selectedCount", [25, 50, 100], 100);
const pageCount = number("Count of pages", 10);
const pageItems = createPageItems(pageCount);
const selectedPageItem = pageItems[0];
const selectedCountItem = countItems[0];
const createPageItems = (count) => {
let pageItems = [];
for (let i = 1; i <= count; i++) {
pageItems.push({
key: i,
label: i + " of " + count,
});
}
return pageItems;
};
return (
<Section>
<Paging
previousLabel={text("previousLabel", "Previous")}
nextLabel={text("nextLabel", "Next")}
pageItems={displayItems ? pageItems : undefined}
selectedPageItem={selectedPageItem}
selectedCountItem={selectedCountItem}
countItems={displayCount ? countItems : undefined}
disablePrevious={boolean("disablePrevious", false)}
disableNext={boolean("disableNext", false)}
previousAction={() => console.log("Prev")}
nextAction={() => console.log("Next")}
openDirection="bottom"
selectedCount={selectedCount}
onSelectPage={(a) => console.log(a)}
onSelectCount={(a) => console.log(a)}
/>
</Section>
);
const countItems = [
{
key: 25,
label: "25 per page",
},
{
key: 50,
label: "50 per page",
},
{
key: 100,
label: "100 per page",
},
];
const selectedCountPageHandler = (count) => {
return countItems.filter((item) => {
if (item.key === count) {
return item;
}
});
};
const Template = ({
pageCount,
displayItems,
displayCount,
nextAction,
previousAction,
onSelectPage,
onSelectCount,
selectedCount,
...args
}) => {
const pageItems = createPageItems(pageCount);
const [selectedPageItem, setSelectedPageItems] = useState(pageItems[0]);
useEffect(() => {
setSelectedPageItems(pageItems[0]);
}, [pageCount]);
const onSelectPageNextHandler = () => {
const currentPage = pageItems.filter(
(item) => item.key === selectedPageItem.key + 1
);
if (currentPage[0]) setSelectedPageItems(currentPage[0]);
};
const onSelectPagePrevHandler = () => {
const currentPage = pageItems.filter(
(item) => item.key === selectedPageItem.key - 1
);
if (currentPage[0]) setSelectedPageItems(currentPage[0]);
};
return (
<div style={{ height: "100px" }}>
<Paging
{...args}
pageItems={displayItems ? pageItems : null}
countItems={displayCount ? countItems : null}
previousAction={() => {
previousAction("Prev");
onSelectPagePrevHandler();
}}
nextAction={() => {
onSelectPageNextHandler();
nextAction("Next");
}}
onSelectPage={(a) => onSelectPage(a)}
onSelectCount={(a) => onSelectCount(a)}
selectedPageItem={selectedPageItem}
selectedCountItem={selectedCountPageHandler(selectedCount)[0]}
/>
</div>
);
};
export const Default = Template.bind({});
Default.args = {
previousLabel: "Previous",
nextLabel: "Next",
displayItems: true,
displayCount: true,
disablePrevious: false,
disableNext: false,
openDirection: "bottom",
selectedCount: 100,
pageCount: 10,
selectedCountItem: {
key: 100,
label: "100 per page",
},
selectedPageItem: { key: 1, label: "1 of 10" },
};

View File

@ -48,11 +48,13 @@ class PasswordInput extends React.Component {
};
onBlur = (e) => {
e.persist();
this.hideTooltip();
if (this.props.onBlur) this.props.onBlur(e);
};
onKeyDown = (e) => {
e.persist();
if (this.props.onKeyDown) this.props.onKeyDown(e);
};
@ -469,52 +471,73 @@ class PasswordInput extends React.Component {
}
PasswordInput.propTypes = {
/** Allows you to set the component id */
id: PropTypes.string,
/** Allows you to set the component auto-complete */
autoComplete: PropTypes.string,
/** It is necessary for correct display of values inside input */
inputType: PropTypes.oneOf(["text", "password"]),
/** Input name */
inputName: PropTypes.string,
/** Required to associate password field with email field */
emailInputName: PropTypes.string,
/** Input value */
inputValue: PropTypes.string,
/** Will be triggered whenever an PasswordInput typing */
onChange: PropTypes.func,
onKeyDown: PropTypes.func,
onBlur: PropTypes.func,
/** If you need to set input width manually */
inputWidth: PropTypes.string,
hasError: PropTypes.bool,
hasWarning: PropTypes.bool,
placeholder: PropTypes.string,
tabIndex: PropTypes.number,
maxLength: PropTypes.number,
/** Accepts class */
className: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Set input disabled */
isDisabled: PropTypes.bool,
size: PropTypes.oneOf(["base", "middle", "big", "huge", "large"]),
scale: PropTypes.bool,
/** Allows to hide NewPasswordButton */
hideNewPasswordButton: PropTypes.bool,
/** Allows to hide Tooltip */
isDisableTooltip: PropTypes.bool,
/** Allows to show text Tooltip */
isTextTooltipVisible: PropTypes.bool,
/** Translation of text for copying email data and password */
clipActionResource: PropTypes.string,
/** Text translation email to copy */
clipEmailResource: PropTypes.string,
/** Text translation password to copy */
clipPasswordResource: PropTypes.string,
/** Text translation copy action to copy */
clipCopiedResource: PropTypes.string,
/** Text translation tooltip */
tooltipPasswordTitle: PropTypes.string,
/** Password text translation is long tooltip */
tooltipPasswordLength: PropTypes.string,
/** Digit text translation tooltip */
tooltipPasswordDigits: PropTypes.string,
/** Capital text translation tooltip */
tooltipPasswordCapital: PropTypes.string,
/** Special text translation tooltip */
tooltipPasswordSpecial: PropTypes.string,
/** Set of special characters for password generator and validator */
generatorSpecial: PropTypes.string,
NewPasswordButtonVisible: PropTypes.bool,
/** Set of settings for password generator and validator */
passwordSettings: PropTypes.object.isRequired,
/** Will be triggered whenever an PasswordInput typing, return bool value */
onValidateInput: PropTypes.func,
/** Will be triggered if you press copy button, return formatted value */
onCopyToClipboard: PropTypes.func,
tooltipOffsetLeft: PropTypes.number,
/** Set simple view of password input (without tooltips, password progress bar and several additional buttons (copy and generate password) */
simpleView: PropTypes.bool,
};

View File

@ -1,83 +1,97 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { StringValue } from "react-values";
import { withKnobs, boolean } from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import React, { useState, useEffect } from "react";
import PasswordInput from ".";
import TextInput from "../text-input";
import Section from "../../../.storybook/decorators/section";
storiesOf("Components|Input", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("password input", () => {
const isDisabled = boolean("isDisabled", false);
const settingsUpperCase = boolean("settingsUpperCase", false);
const settingsDigits = boolean("settingsDigits", false);
const settingsSpecSymbols = boolean("settingsSpecSymbols", false);
const simpleView = boolean("simpleView", false);
const hideNewPasswordButton = boolean("hideNewPasswordButton", false);
const isDisableTooltip = boolean("isDisableTooltip", false);
const isTextTooltipVisible = boolean("isTextTooltipVisible", false);
const Template = ({
settingMinLength,
settingsUpperCase,
settingsDigits,
settingsSpecSymbols,
tooltipPasswordLength,
onChange,
onValidateInput,
onCopyToClipboard,
...args
}) => {
const [value, setValue] = useState("");
const [fakeSettings, setFakSettings] = useState();
const fakeSettings = {
minLength: 6,
useEffect(() => {
setFakSettings({
minLength: settingMinLength,
upperCase: settingsUpperCase,
digits: settingsDigits,
specSymbols: settingsSpecSymbols,
};
});
setValue("");
}, [
settingMinLength,
settingsUpperCase,
settingsDigits,
settingsSpecSymbols,
]);
const tooltipPasswordLength =
"from " + fakeSettings.minLength + " to 30 characters";
const onChangeHandler = (e) => {
onChange(e.currentTarget.value);
setValue(e.currentTarget.value);
};
return (
<Section>
<div style={{ height: "110px" }}></div>
<TextInput
name="demoEmailInput"
size="base"
isDisabled={isDisabled}
isReadOnly={true}
scale={true}
value="demo@gmail.com"
/>
<br />
<StringValue>
{({ value, set }) => (
<PasswordInput
simpleView={simpleView}
inputName="demoPasswordInput"
emailInputName="demoEmailInput"
inputValue={value}
onChange={(e) => {
set(e.target.value);
}}
clipActionResource="Copy e-mail and password"
clipEmailResource="E-mail: "
clipPasswordResource="Password: "
clipCopiedResource="Copied"
hideNewPasswordButton={hideNewPasswordButton}
isDisableTooltip={isDisableTooltip}
isTextTooltipVisible={isTextTooltipVisible}
tooltipPasswordTitle="Password must contain:"
tooltipPasswordLength={tooltipPasswordLength}
tooltipPasswordDigits="digits"
tooltipPasswordCapital="capital letters"
tooltipPasswordSpecial="special characters (!@#$%^&*)"
generatorSpecial="!@#$%^&*"
passwordSettings={fakeSettings}
isDisabled={isDisabled}
placeholder="password"
maxLength={30}
onValidateInput={(a) => console.log(a)}
onCopyToClipboard={(b) =>
console.log("Data " + b + " copied to clipboard")
}
//tooltipOffsetLeft={150}
/>
)}
</StringValue>
</Section>
);
});
const onValidateInputHandler = (e) => {
onValidateInput(e);
};
const onCopyToClipboardHandler = (e) => {
onCopyToClipboard(`Data ${e} copied to clipboard`);
};
return (
<div style={{ height: "110px", display: "grid", gridGap: "24px" }}>
<TextInput
name="demoEmailInput"
size="base"
isDisabled={args.isDisabled}
isReadOnly={true}
scale={true}
value="demo@gmail.com"
/>
<PasswordInput
{...args}
inputValue={value}
onChange={onChangeHandler}
tooltipPasswordLength={`${tooltipPasswordLength} ${settingMinLength}`}
passwordSettings={fakeSettings}
onValidateInput={onValidateInputHandler}
onCopyToClipboard={onCopyToClipboardHandler}
tooltipOffsetLeft={150}
/>
</div>
);
};
export const basic = Template.bind({});
basic.args = {
isDisabled: false,
settingMinLength: 6,
settingsUpperCase: false,
settingsDigits: false,
settingsSpecSymbols: false,
simpleView: false,
inputName: "demoPasswordInput",
emailInputName: "demoEmailInput",
hideNewPasswordButton: false,
isDisableTooltip: false,
isTextTooltipVisible: false,
clipActionResource: "Copy e-mail and password",
clipEmailResource: "E-mail: ",
clipPasswordResource: "Password: ",
clipCopiedResource: "Copied",
tooltipPasswordTitle: "Password must contain:",
tooltipPasswordLength: "minimum length: ",
tooltipPasswordDigits: "digits",
tooltipPasswordCapital: "capital letters",
tooltipPasswordSpecial: "special characters (!@#$%^&*)",
generatorSpecial: "!@#$%^&*",
placeholder: "password",
maxLength: 30,
};

View File

@ -0,0 +1,63 @@
import { Meta, Story, ArgsTable, Canvas } from "@storybook/addon-docs/blocks";
import PasswordInput from "./";
import * as stories from "./password-input.stories.js";
import InputBlock from "../input-block";
<Meta
title="Components/PasswordInput"
component={PasswordInput}
subcomponents={{ InputBlock }}
argTypes={{
onChange: { action: "onChange" },
onValidateInput: { action: "onValidateInput" },
onCopyToClipboard: { action: "onCopyToClipboard" },
onKeyDown: { onKeyDown: "onKeyDown" },
}}
/>
# PasswordInput
Password entry field with advanced capabilities for displaying, validation of correspondence and generation based on settings
<Canvas>
<Story story={stories.basic} name="Default" />
</Canvas>
### Properties
You can apply all the parameters of the InputBlock component to the component.
<ArgsTable story="Default" />
## Description
#### Object with settings:
```js
{
minLength: 6,
upperCase: false,
digits: false,
specSymbols: false
}
```
Check for compliance with settings is carried out on fly. As you type in required number of characters, progress bar will fill up and when all conditions are met, the color will change from red to green.
Depending on screen width of device, input will change location of elements.
When setting focus to input, tooltip will be shown with progress in fulfilling conditions specified in settings. When unfocused, tooltip disappears.
When button is pressed, copy data will be copied to clipboard and copy action will be blocked for 2 seconds. In future, the button is unlocked.
If emailInputName parameter value is empty, copy action will be disabled.
#### passwordSettings properties
| Props | Type | Required | Values | Default | Description |
| ------------- | :------: | :------: | :----: | :-----: | ------------------------------- |
| `digits` | `bool` | ✅ | - | - | Must contain digits |
| `minLength` | `number` | ✅ | - | - | Minimum password length |
| `specSymbols` | `bool` | ✅ | - | - | Must contain special characters |
| `upperCase` | `bool` | ✅ | - | - | Must contain uppercase letters |

View File

@ -3,8 +3,7 @@ import PropTypes from "prop-types";
import DropDown from "../drop-down";
import Link from "./link";
import StyledProgressBar from "./styled-progress-bar"
import StyledProgressBar from "./styled-progress-bar";
const ProgressBar = (props) => {
const { percent, label, dropDownContent, ...rest } = props;
@ -62,8 +61,11 @@ const ProgressBar = (props) => {
};
ProgressBar.propTypes = {
/** Progress value. */
percent: PropTypes.number.isRequired,
/** Text in progress-bar. */
label: PropTypes.string,
/** Drop-down content. */
dropDownContent: PropTypes.any,
};

View File

@ -1,18 +1,25 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import { withKnobs, number, text } from "@storybook/addon-knobs/react";
import ProgressBar from "./";
storiesOf("Components|ProgressBar", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("base", () => (
<ProgressBar
style={{ marginTop: 16 }}
label={text("label", "Uploading files: 20 of 100")}
percent={number("value", 20)}
dropDownContent={text("dropDownContent", "You content here")}
/>
));
export default {
title: "Components/ProgressBar",
component: ProgressBar,
parameters: {
docs: {
description: {
component:
"A container that displays a process or operation as a progress bar",
},
},
},
};
const Template = (args) => {
return <ProgressBar {...args} style={{ marginTop: 16 }} />;
};
export const Default = Template.bind({});
Default.args = {
label: "Uploading files: 20 of 100",
percent: 20,
dropDownContent: "You content here",
};

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.97 12.91L1 6.94L2.94 5L6.97 9.03L13 3L14.94 4.94L6.97 12.91Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 192 B

View File

@ -60,9 +60,13 @@ class RadioButtonGroup extends React.Component {
}
RadioButtonGroup.propTypes = {
/** Disabling all radiobutton in group */
isDisabled: PropTypes.bool,
/** Used as HTML `name` property for `<input>` tag. Used for identification RadioButtonGroup */
name: PropTypes.string.isRequired,
/** Allow you to handle clicking events on `<RadioButton />` component */
onClick: PropTypes.func,
/** Array of objects, contains props for each `<RadioButton />` component */
options: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.string.isRequired,
@ -70,14 +74,24 @@ RadioButtonGroup.propTypes = {
disabled: PropTypes.bool,
})
).isRequired,
/** Value of the selected radiobutton */
selected: PropTypes.string.isRequired,
/** Margin between radiobutton. If orientation `horizontal`, it is `margin-left`(apply for all radiobuttons,
* except first), if orientation `vertical`, it is `margin-bottom`(apply for all radiobuttons, except last) */
spacing: PropTypes.string,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Position of radiobuttons */
orientation: PropTypes.oneOf(["horizontal", "vertical"]),
/** Width of RadioButtonGroup container */
width: PropTypes.string,
/** Font size of link */
fontSize: PropTypes.string,
/** Font weight of link */
fontWeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
};

View File

@ -1,79 +1,100 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import withReadme from "storybook-readme/with-readme";
import RadioButtonGroup from ".";
import Section from "../../../.storybook/decorators/section";
import { withKnobs, text, boolean, select } from "@storybook/addon-knobs/react";
import Readme from "./README.md";
import { action } from "@storybook/addon-actions";
import { optionsKnob as options } from "@storybook/addon-knobs";
import RadioButtonGroup from "./";
storiesOf("Components|Input", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("radio button group", () => {
const orientation = ["horizontal", "vertical"];
const values = ["first", "second", "third"];
const valuesMultiSelect = {
radio1: "radio1",
radio2: "radio2",
radio3: "radio3",
};
export default {
title: "Components/RadioButtonGroup",
component: RadioButtonGroup,
parameters: {
docs: {
description: {
component: "RadioButtonGroup allow you to add group radiobutton",
},
},
},
argTypes: {
options: {
control: {
type: "multi-select",
options: ["radio1", "radio2", "radio3"],
},
},
onClick: {
cation: "onClick",
},
labelFirst: {
description: "Label for 1st radiobutton (only storybook)",
control: "text",
},
labelSecond: {
description: "Label for 2nd radiobutton (only storybook)",
control: "text",
},
labelThird: {
description: "Label for 3rd radiobutton (only storybook)",
control: "text",
},
},
};
const optionsMultiSelect = options(
"options",
valuesMultiSelect,
["radio1", "radio2"],
{
display: "multi-select",
}
);
let children = [];
optionsMultiSelect.forEach(function (item) {
const Template = ({
options,
onClick,
labelFirst,
labelSecond,
labelThird,
...args
}) => {
const values = ["first", "second", "third"];
const updateOptions = (options) => {
const updatedOptions = options.map((item) => {
switch (item) {
case "radio1":
children.push({
return {
value: values[0],
label: text("label 1", "First radiobtn"),
});
break;
label: labelFirst,
};
case "radio2":
children.push({
return {
value: values[1],
label: text("label 2", "Second radiobtn"),
});
break;
label: labelSecond,
};
case "radio3":
children.push({
return {
value: values[2],
label: text("label 3", "Third radiobtn"),
});
break;
label: labelThird,
};
default:
break;
}
});
return updatedOptions;
};
return (
<Section>
<>
<RadioButtonGroup
onClick={(e) => {
action("onChange")(e);
console.log("Value of selected radiobutton: ", e.target.value);
}}
orientation={select("orientation", orientation, "horizontal")}
width={text("width", "100%")}
isDisabled={boolean("isDisabled", false)}
fontSize={text("fontSize", "13px")}
fontWeight={text("fontWeight", "400")}
selected={values[0]}
spacing={text("spacing", "15px")}
name={text("name", "group")}
options={children}
/>
</>
</Section>
);
});
const updatedOptions = updateOptions(options);
return (
<RadioButtonGroup
{...args}
options={updatedOptions}
selected={updatedOptions[0].value}
onClick={(e) => {
onClick(e);
}}
/>
);
};
export const Default = Template.bind({});
Default.args = {
orientation: "horizontal",
width: "100%",
isDisabled: false,
fontSize: "13px",
fontWeight: "400",
spacing: "15px",
name: "group",
options: ["radio1", "radio3"],
labelFirst: "First radiobtn",
labelSecond: "Second radiobtn",
labelThird: "Third radiobtn",
};

View File

@ -78,19 +78,34 @@ class RadioButton extends React.Component {
}
RadioButton.propTypes = {
/** Used as HTML `checked` property for each `<input>` tag */
isChecked: PropTypes.bool,
/** Used as HTML `disabled` property for each `<input>` tag */
isDisabled: PropTypes.bool,
/** Name of the radiobutton. If missed, `value` will be used */
label: PropTypes.string,
/** Font size of link */
fontSize: PropTypes.string,
/** Font weight of link */
fontWeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
/** Used as HTML `name` property for `<input>` tag. */
name: PropTypes.string.isRequired,
onChange: PropTypes.func,
/** Allow you to handle clicking events on component */
onClick: PropTypes.func,
/** Used as HTML `value` property for `<input>` tag. Used for identification each radiobutton */
value: PropTypes.string.isRequired,
/** Margin between radiobutton. If orientation `horizontal`,
* it is `margin-left`(apply for all radiobuttons, except first),
* if orientation `vertical`, it is `margin-bottom`(apply for all radiobuttons, except last) */
spacing: PropTypes.string,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Position of radiobuttons */
orientation: PropTypes.oneOf(["horizontal", "vertical"]),
};

View File

@ -1,33 +1,40 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import withReadme from "storybook-readme/with-readme";
import React, { useState, useEffect } from "react";
import RadioButton from ".";
import Section from "../../../.storybook/decorators/section";
import { withKnobs, text, boolean } from "@storybook/addon-knobs/react";
import Readme from "./README.md";
storiesOf("Components|Input", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("radio button", () => {
return (
<Section>
<RadioButton
value={text("value", "value")}
name={text("name", "name")}
label={text("label", "Label")}
fontSize={text("fontSize", "13px")}
fontWeight={text("fontWeight", "400")}
isDisabled={boolean("isDisabled", false)}
isChecked={boolean("isChecked", false)}
onClick={(e) => {
window.__STORYBOOK_ADDONS.channel.emit("storybookjs/knobs/change", {
name: "isChecked",
value: e.target.checked,
});
console.log("onChange", e);
}}
/>
</Section>
);
});
export default {
title: "Components/RadioButton",
component: RadioButton,
parameters: {
docs: {
description: { component: "RadioButton allow you to add radiobutton" },
},
},
argTypes: {},
};
const Template = ({ isChecked, ...args }) => {
const [checked, setIsChecked] = useState(isChecked);
useEffect(() => {
setIsChecked(isChecked);
}, [isChecked]);
const onChangeHandler = (e) => {
setIsChecked(e.target.checked);
};
return (
<RadioButton {...args} isChecked={checked} onChange={onChangeHandler} />
);
};
export const Default = Template.bind({});
Default.args = {
value: "value",
name: "name",
label: "Label",
fontSize: "13px",
fontWeight: "400",
isDisabled: false,
isChecked: false,
};

View File

@ -24,15 +24,25 @@ const RequestLoader = (props) => {
};
RequestLoader.propTypes = {
/** Visibility */
visible: PropTypes.bool,
/** CSS z-index */
zIndex: PropTypes.number,
/** Svg height and width value */
loaderSize: PropTypes.string,
/** Svg color */
loaderColor: PropTypes.string,
/** Svg aria-label and text label */
label: PropTypes.string,
/** Text label font size */
fontSize: PropTypes.string,
/** Text label font color */
fontColor: PropTypes.string,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

View File

@ -1,30 +1,34 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import {
withKnobs,
boolean,
number,
text,
color,
} from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import RequestLoader from ".";
import Section from "../../../.storybook/decorators/section";
import RequestLoader from "./";
storiesOf("Components|Loaders", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("request-loader", () => (
<Section>
<RequestLoader
visible={boolean("visible", true)}
zIndex={number("zIndex", 256)}
loaderSize={text("loaderSize", "16px")}
loaderColor={color("loaderColor", "#999")}
label={text("label", "Loading... Please wait...")}
fontSize={text("fontSize", "12px")}
fontColor={color("fontColor", "#999")}
/>
</Section>
));
export default {
title: "Components/Loaders",
component: RequestLoader,
parameters: {
docs: {
description: {
component:
"equestLoader component is used for displaying loading actions on a page",
},
},
},
argTypes: {
loaderColor: { control: "color" },
fontColor: { control: "color" },
},
};
const Template = (args) => {
return <RequestLoader {...args} />;
};
export const Default = Template.bind({});
Default.args = {
visible: true,
zIndex: 256,
loaderSize: "16px",
loaderColor: "#999",
label: "Loading... Please wait...",
fontSize: "12px",
fontColor: "#999",
};

View File

@ -103,12 +103,19 @@ class RowContainer extends React.PureComponent {
}
RowContainer.propTypes = {
/** Height of one Row element. Required for scroll to work properly */
itemHeight: PropTypes.number,
/** Allows you to set fixed block height for Row */
manualHeight: PropTypes.string,
/** Child elements */
children: PropTypes.any.isRequired,
/** Use react-window for efficiently rendering large lists */
useReactWindow: PropTypes.bool,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

View File

@ -1,20 +1,28 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import Section from "../../../.storybook/decorators/section";
import RowContainer from ".";
import Row from "../row";
import RowContent from "../row-content";
import Avatar from "../avatar";
import Link from "../link";
import SendClockIcon from "../../../../../public/images/send.clock.react.svg";
import CatalogSpamIcon from "../../../../../public/images/catalog.spam.react.svg";
import SendClockIcon from "../public/static/images/send.clock.react.svg";
import CatalogSpamIcon from "../public/static/images/catalog.spam.react.svg";
export default {
title: "Components/RowContainer",
component: RowContainer,
subcomponents: { Row, RowContent },
parameters: {
docs: { description: { component: "Container for Row component" } },
},
};
const getRndString = (n) =>
Math.random()
.toString(36)
.substring(2, n + 2);
const getRndNumber = (a, b) => Math.floor(Math.random() * (b - a)) + a;
const getRndBool = () => Math.random() >= 0.5;
const fillFakeData = (n) => {
@ -56,104 +64,93 @@ const fillFakeData = (n) => {
const fakeData = fillFakeData(20);
storiesOf("Components|RowContainer", module)
.addDecorator(withReadme(Readme))
.add("base", () => {
return (
<Section>
<RowContainer manualHeight="500px">
{fakeData.map((user) => {
const element = (
<Avatar
size="min"
role={user.role}
userName={user.userName}
source={user.avatar}
/>
);
const nameColor = user.status === "pending" ? "#A3A9AE" : "#333333";
const sideInfoColor =
user.status === "pending" ? "#D0D5DA" : "#A3A9AE";
const Template = (args) => {
return (
<RowContainer {...args} manualHeight="500px">
{fakeData.map((user) => {
const element = (
<Avatar
size="min"
role={user.role}
userName={user.userName}
source={user.avatar}
/>
);
const nameColor = user.status === "pending" ? "#A3A9AE" : "#333333";
const sideInfoColor = user.status === "pending" ? "#D0D5DA" : "#A3A9AE";
return (
<Row
key={user.id}
status={user.status}
checked={false}
data={user}
element={element}
contextOptions={user.contextOptions}
return (
<Row
key={user.id}
status={user.status}
checked={false}
data={user}
element={element}
contextOptions={user.contextOptions}
>
<RowContent>
<Link
type="page"
title={user.userName}
isBold={true}
fontSize="15px"
color={nameColor}
>
<RowContent>
<Link
type="page"
title={user.userName}
isBold={true}
fontSize="15px"
color={nameColor}
>
{user.userName}
</Link>
<>
{user.status === "pending" && (
<SendClockIcon
size="small"
isfill={true}
color="#3B72A7"
/>
)}
{user.status === "disabled" && (
<CatalogSpamIcon
size="small"
isfill={true}
color="#3B72A7"
/>
)}
</>
{user.isHead ? (
<Link
containerWidth="120px"
type="page"
title="Head of department"
fontSize="12px"
color={sideInfoColor}
>
Head of department
</Link>
) : (
<div></div>
)}
<Link
containerWidth="160px"
type="action"
title={user.department}
fontSize="12px"
color={sideInfoColor}
>
{user.department}
</Link>
<Link
type="page"
title={user.mobilePhone}
fontSize="12px"
color={sideInfoColor}
>
{user.mobilePhone}
</Link>
<Link
containerWidth="180px"
type="page"
title={user.email}
fontSize="12px"
color={sideInfoColor}
>
{user.email}
</Link>
</RowContent>
</Row>
);
})}
</RowContainer>
</Section>
);
});
{user.userName}
</Link>
<>
{user.status === "pending" && (
<SendClockIcon size="small" isfill={true} color="#3B72A7" />
)}
{user.status === "disabled" && (
<CatalogSpamIcon size="small" isfill={true} color="#3B72A7" />
)}
</>
{user.isHead ? (
<Link
containerWidth="120px"
type="page"
title="Head of department"
fontSize="12px"
color={sideInfoColor}
>
Head of department
</Link>
) : (
<div></div>
)}
<Link
containerWidth="160px"
type="action"
title={user.department}
fontSize="12px"
color={sideInfoColor}
>
{user.department}
</Link>
<Link
type="page"
title={user.mobilePhone}
fontSize="12px"
color={sideInfoColor}
>
{user.mobilePhone}
</Link>
<Link
containerWidth="180px"
type="page"
title={user.email}
fontSize="12px"
color={sideInfoColor}
>
{user.email}
</Link>
</RowContent>
</Row>
);
})}
</RowContainer>
);
};
export const Default = Template.bind({});

View File

@ -113,12 +113,18 @@ const RowContent = (props) => {
};
RowContent.propTypes = {
/** Components displayed inside RowContent */
children: PropTypes.node.isRequired,
/** Accepts class */
className: PropTypes.string,
/** If you do not need SideElements */
disableSideInfo: PropTypes.bool,
/** Accepts id */
id: PropTypes.string,
onClick: PropTypes.func,
/** Need for change side information color */
sideColor: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
sectionWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
isMobile: PropTypes.bool,

View File

@ -1,287 +1,188 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { BooleanValue } from "react-values";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import Section from "../../../.storybook/decorators/section";
import RowContent from ".";
import React, { useState } from "react";
import RowContent from "./";
import Link from "../link";
import Checkbox from "../checkbox";
import SendClockIcon from "../../../../../public/images/send.clock.react.svg";
import CatalogSpamIcon from "../../../../../public/images/catalog.spam.react.svg";
storiesOf("Components|RowContent", module)
.addDecorator(withReadme(Readme))
.add("base", () => {
return (
<Section>
<h3>Base demo</h3>
<div style={{ height: "16px" }}></div>
<RowContent>
<Link
type="page"
title="Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo
</Link>
<>
<SendClockIcon size="small" isfill={true} color="#3B72A7" />
<CatalogSpamIcon size="small" isfill={true} color="#3B72A7" />
</>
<Link type="page" title="Demo" fontSize="12px" color="#A3A9AE">
Demo
</Link>
<Link
containerWidth="160px"
type="action"
title="Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo
</Link>
<Link
type="page"
title="0 000 0000000"
fontSize="12px"
color="#A3A9AE"
>
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo@demo.com
</Link>
</RowContent>
<RowContent>
<Link
type="page"
title="Demo Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo Demo
</Link>
<>
<CatalogSpamIcon size="small" isfill={true} color="#3B72A7" />
</>
<></>
<Link
containerWidth="160px"
type="action"
title="Demo Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo Demo
</Link>
<Link
type="page"
title="0 000 0000000"
fontSize="12px"
color="#A3A9AE"
>
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo.demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo.demo@demo.com
</Link>
</RowContent>
<RowContent>
<Link
type="page"
title="Demo Demo Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo Demo Demo
</Link>
<></>
<></>
<Link
containerWidth="160px"
type="action"
title="Demo Demo Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo Demo Demo
</Link>
<Link
type="page"
title="0 000 0000000"
fontSize="12px"
color="#A3A9AE"
>
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo.demo.demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo.demo.demo@demo.com
</Link>
</RowContent>
<RowContent>
<Link
type="page"
title="Demo Demo Demo Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo Demo Demo Demo
</Link>
<>
<SendClockIcon size="small" isfill={true} color="#3B72A7" />
</>
<Link type="page" title="Demo" fontSize="12px" color="#A3A9AE">
Demo
</Link>
<Link
containerWidth="160px"
type="action"
title="Demo Demo Demo Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo Demo Demo Demo
</Link>
<Link
type="page"
title="0 000 0000000"
fontSize="12px"
color="#A3A9AE"
>
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo.demo.demo.demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo.demo.demo.demo@demo.com
</Link>
</RowContent>
<div style={{ height: "36px" }}></div>
<h3>Custom elements</h3>
<div style={{ height: "16px" }}></div>
<RowContent disableSideInfo={true}>
<Link
type="page"
title="John Doe"
isBold={true}
fontSize="15px"
color="#333333"
>
John Doe
</Link>
<></>
<BooleanValue>
{({ value, toggle }) => (
<Checkbox
id="1"
name="sample"
isChecked={value}
onChange={(e) => {
toggle(e.target.checked);
}}
/>
)}
</BooleanValue>
<BooleanValue>
{({ value, toggle }) => (
<Checkbox
id="2"
name="sample"
isChecked={value}
onChange={(e) => {
toggle(e.target.checked);
}}
/>
)}
</BooleanValue>
<BooleanValue>
{({ value, toggle }) => (
<Checkbox
id="3"
name="sample"
isChecked={value}
onChange={(e) => {
toggle(e.target.checked);
}}
/>
)}
</BooleanValue>
<BooleanValue>
{({ value, toggle }) => (
<Checkbox
id="4"
name="sample"
isChecked={value}
onChange={(e) => {
toggle(e.target.checked);
}}
/>
)}
</BooleanValue>
<BooleanValue>
{({ value, toggle }) => (
<Checkbox
id="5"
name="sample"
isChecked={value}
onChange={(e) => {
toggle(e.target.checked);
}}
/>
)}
</BooleanValue>
<BooleanValue>
{({ value, toggle }) => (
<Checkbox
id="6"
name="sample"
isChecked={value}
onChange={(e) => {
toggle(e.target.checked);
}}
/>
)}
</BooleanValue>
<BooleanValue>
{({ value, toggle }) => (
<Checkbox
id="7"
name="sample"
isChecked={value}
onChange={(e) => {
toggle(e.target.checked);
}}
/>
)}
</BooleanValue>
</RowContent>
</Section>
);
});
import SendClockIcon from "../public/static/images/send.clock.react.svg";
import CatalogSpamIcon from "../public/static/images/catalog.spam.react.svg";
const Template = (args) => {
const [isChecked, setIsChecked] = useState(false);
return (
<>
<h3>Base demo</h3>
<div style={{ height: "16px" }}></div>
<RowContent {...args}>
<Link
type="page"
title="Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo
</Link>
<>
<SendClockIcon size="small" isfill={true} color="#3B72A7" />
<CatalogSpamIcon size="small" isfill={true} color="#3B72A7" />
</>
<Link type="page" title="Demo" fontSize="12px" color="#A3A9AE">
Demo
</Link>
<Link
containerWidth="160px"
type="action"
title="Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo
</Link>
<Link type="page" title="0 000 0000000" fontSize="12px" color="#A3A9AE">
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo@demo.com
</Link>
</RowContent>
<RowContent>
<Link
type="page"
title="Demo Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo Demo
</Link>
<>
<CatalogSpamIcon size="small" isfill={true} color="#3B72A7" />
</>
<></>
<Link
containerWidth="160px"
type="action"
title="Demo Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo Demo
</Link>
<Link type="page" title="0 000 0000000" fontSize="12px" color="#A3A9AE">
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo.demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo.demo@demo.com
</Link>
</RowContent>
<RowContent>
<Link
type="page"
title="Demo Demo Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo Demo Demo
</Link>
<></>
<></>
<Link
containerWidth="160px"
type="action"
title="Demo Demo Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo Demo Demo
</Link>
<Link type="page" title="0 000 0000000" fontSize="12px" color="#A3A9AE">
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo.demo.demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo.demo.demo@demo.com
</Link>
</RowContent>
<RowContent>
<Link
type="page"
title="Demo Demo Demo Demo"
isBold={true}
fontSize="15px"
color="#333333"
>
Demo Demo Demo Demo
</Link>
<>
<SendClockIcon size="small" isfill={true} color="#3B72A7" />
</>
<Link type="page" title="Demo" fontSize="12px" color="#A3A9AE">
Demo
</Link>
<Link
containerWidth="160px"
type="action"
title="Demo Demo Demo Demo"
fontSize="12px"
color="#A3A9AE"
>
Demo Demo Demo Demo
</Link>
<Link type="page" title="0 000 0000000" fontSize="12px" color="#A3A9AE">
0 000 0000000
</Link>
<Link
containerWidth="160px"
type="page"
title="demo.demo.demo.demo@demo.com"
fontSize="12px"
color="#A3A9AE"
>
demo.demo.demo.demo@demo.com
</Link>
</RowContent>
<div style={{ height: "36px" }}></div>
<h3>Custom elements</h3>
<div style={{ height: "16px" }}></div>
<RowContent disableSideInfo={true}>
<Link
type="page"
title="John Doe"
isBold={true}
fontSize="15px"
color="#333333"
>
John Doe
</Link>
<></>
<Checkbox
id="1"
name="sample"
isChecked={isChecked}
onChange={(e) => {
setIsChecked(e.target.checked);
}}
/>
</RowContent>
</>
);
};
export const basic = Template.bind({});

View File

@ -0,0 +1,28 @@
import { Meta, Story, ArgsTable, Canvas } from "@storybook/addon-docs/blocks";
import RowContent from "./";
import * as stories from "./row-content.stories.js";
<Meta title="Components/RowContent" component={RowContent} />
# RowContent
Required for formatted output of elements inside Row
<Canvas>
<Story story={stories.basic} name="Default" />
</Canvas>
<ArgsTable story="Default" />
## Description
To correctly display components inside RowContent, you must specify them in a certain order.
The first and second specified components will be interpreted as Main elements.
First will be MainTitle and second MainIcons.
All subsequent components will be located on the right and are considered SideElements.
**_Consider location of components in advance, since when viewing in tablet mode, the markup will shift SideElements to second line._**
Each not main child can take containerWidth property for task of width of child's container.

View File

@ -125,19 +125,32 @@ class Row extends React.Component {
}
Row.propTypes = {
/** Required to host the Checkbox component. Its location is fixed and it is always the first.
* If there is no value, the occupied space is distributed among the other child elements. */
checked: PropTypes.bool,
children: PropTypes.element,
/** Accepts class */
className: PropTypes.string,
contentElement: PropTypes.any,
/** Required for the width task of the ContextMenuButton component. */
contextButtonSpacerWidth: PropTypes.string,
/** Required to host the ContextMenuButton component. It is always located near the right border of the container,
* regardless of the contents of the child elements. If there is no value, the occupied space is distributed among the other child elements. */
contextOptions: PropTypes.array,
/** Current row item information. */
data: PropTypes.object,
/** Required to host some component. It has a fixed order of location, if the Checkbox component is specified,
* then it follows, otherwise it occupies the first position. If there is no value, the occupied space is distributed among the other child elements. */
element: PropTypes.element,
/** Accepts id */
id: PropTypes.string,
indeterminate: PropTypes.bool,
/** shouldComponentUpdate function */
needForUpdate: PropTypes.func,
/** when selecting row element. Returns data value. */
onSelect: PropTypes.func,
selectItem: PropTypes.func,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
sectionWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};

View File

@ -1,85 +1,109 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { withKnobs, boolean, text, select } from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import Row from ".";
import Text from "../text";
import Avatar from "../avatar";
import ComboBox from "../combobox";
import Section from "../../../.storybook/decorators/section";
import CatalogFolderIcon from "../../../../../public/images/catalog.folder.react.svg";
storiesOf("Components|Row", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("base", () => {
const contextButton = boolean("contextButton", true);
const checked = boolean("checkbox", true);
const element = select("element", ["", "Avatar", "Icon", "ComboBox"], "");
import CatalogFolderIcon from "../public/static/images/catalog.folder.react.svg";
const elementAvatar = (
<Avatar size="min" role="user" userName="Demo Avatar" />
);
const elementIcon = <CatalogFolderIcon size="big" />;
const elementComboBox = (
<ComboBox
options={[
{
key: 1,
icon: "static/images/item.active.react.svg",
label: "Open",
},
{ key: 2, icon: "CheckIcon", label: "Closed" },
]}
onSelect={(option) => console.log(option)}
selectedOption={{
key: 0,
icon: "static/images/item.active.react.svg",
label: "",
}}
scaled={false}
size="content"
isDisabled={false}
/>
);
export default {
title: "Components/Row",
component: Row,
parameters: {
docs: { description: { component: "Displays content as row" } },
},
argTypes: {
element: {
control: {
type: "select",
options: ["", "Avatar", "Icon", "ComboBox"],
},
},
content: { control: "text" },
onSelectComboBox: { action: "onSelectComboBox", table: { disable: true } },
contextItemClick: { action: "contextItemClick", table: { disable: true } },
checkbox: { description: "Disable checkbox" },
},
};
const checkedProps = checked ? { checked: false } : {};
const getElementProps = (element) =>
element === "Avatar"
? { element: elementAvatar }
: element === "Icon"
? { element: elementIcon }
: element === "ComboBox"
? { element: elementComboBox }
: {};
const elementAvatar = <Avatar size="min" role="user" userName="Demo Avatar" />;
const elementIcon = <CatalogFolderIcon size="big" />;
const elementProps = getElementProps(element);
const renderElementComboBox = (onSelect) => (
<ComboBox
options={[
{
key: 1,
icon: "static/images/item.active.react.svg",
label: "Open",
},
{ key: 2, icon: "static/images/check.react.svg", label: "Closed" },
]}
onSelect={(option) => onSelect(option)}
selectedOption={{
key: 0,
icon: "static/images/item.active.react.svg",
label: "",
}}
scaled={false}
size="content"
isDisabled={false}
/>
);
return (
<Section>
<Row
key="1"
{...checkedProps}
{...elementProps}
contextOptions={
contextButton
? [
{
key: "key1",
label: "Edit",
onClick: () => console.log("Context action: Edit"),
},
{
key: "key2",
label: "Delete",
onClick: () => console.log("Context action: Delete"),
},
]
: []
}
>
<Text truncate={true}>{text("content", "Sample text")}</Text>
</Row>
</Section>
);
});
const Template = ({
element,
contextButton,
content,
onSelectComboBox,
contextItemClick,
checkbox,
checked,
...args
}) => {
const getElementProps = (element) =>
element === "Avatar"
? { element: elementAvatar }
: element === "Icon"
? { element: elementIcon }
: element === "ComboBox"
? { element: renderElementComboBox(onSelectComboBox) }
: {};
const elementProps = getElementProps(element);
const checkedProps = checkbox ? { checked: checked } : {};
return (
<Row
{...args}
key="1"
{...checkedProps}
{...elementProps}
contextOptions={
contextButton
? [
{
key: "key1",
label: "Edit",
onClick: () => contextItemClick("Context action: Edit"),
},
{
key: "key2",
label: "Delete",
onClick: () => contextItemClick("Context action: Delete"),
},
]
: []
}
>
<Text truncate={true}>{content}</Text>
</Row>
);
};
export const Default = Template.bind({});
Default.args = {
contextButton: true,
checked: true,
element: "",
content: "Sample text",
checkbox: true,
};

View File

@ -72,13 +72,21 @@ class SaveCancelButtons extends React.Component {
}
SaveCancelButtons.propTypes = {
/** Accepts css id */
id: PropTypes.string,
/** Accepts css class */
className: PropTypes.string,
/** Text reminding of unsaved changes */
reminderTest: PropTypes.string,
/** Save button label */
saveButtonLabel: PropTypes.string,
/** Cancel button label */
cancelButtonLabel: PropTypes.string,
/** What the save button will trigger when clicked */
onSaveClick: PropTypes.func,
/** What the cancel button will trigger when clicked */
onCancelClick: PropTypes.func,
/** Show message about unsaved changes (Only shown on desktops) */
showReminder: PropTypes.bool,
};

View File

@ -1,26 +1,39 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { text, boolean, withKnobs } from "@storybook/addon-knobs/react";
import SaveCancelButtons from ".";
import Section from "../../../.storybook/decorators/section";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import SaveCancelButtons from "./";
storiesOf("Components|SaveCancelButtons", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("base", () => {
return (
<Section>
<SaveCancelButtons
onSaveClick={() => action("on Save button clicked")}
onCancelClick={() => action("on Cancel button clicked")}
showReminder={boolean("showReminder", false)}
reminderTest={text("reminderTest", "You have unsaved changes")}
saveButtonLabel={text("saveButtonLabel", "Save")}
cancelButtonLabel={text("cancelButtonLabel", "Cancel")}
/>
</Section>
);
});
export default {
title: "Components/SaveCancelButtons",
component: SaveCancelButtons,
parameters: {
docs: {
description: {
component:
"Save and cancel buttons are located in the settings sections.",
},
},
},
argTypes: {
onSaveClick: { action: "onSaveClick" },
onCancelClick: { action: "onCancelClick" },
},
};
const Template = ({ onSaveClick, onCancelClick, ...args }) => {
return (
<div style={{ position: "relative", height: "60px" }}>
<SaveCancelButtons
{...args}
onSaveClick={() => onSaveClick("on Save button clicked")}
onCancelClick={() => onCancelClick("on Cancel button clicked")}
/>
</div>
);
};
export const Default = Template.bind({});
Default.args = {
showReminder: false,
reminderTest: "You have unsaved changes",
saveButtonLabel: "Save",
cancelButtonLabel: "Cancel",
};

View File

@ -103,9 +103,13 @@ const Scrollbar = React.forwardRef((props, ref) => {
});
Scrollbar.propTypes = {
/** Scrollbar style type */
stype: PropTypes.string,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

View File

@ -1,37 +1,42 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import withReadme from "storybook-readme/with-readme";
import { withKnobs, select } from "@storybook/addon-knobs/react";
import Readme from "./README.md";
import Section from "../../../.storybook/decorators/section";
import Scrollbar from ".";
import Scrollbar from "./";
const stypes = ["smallWhite", "smallBlack", "mediumBlack"];
export default {
title: "Components/Scrollbar",
component: Scrollbar,
parameters: {
docs: {
description: {
component: "Scrollbar is used for displaying custom scrollbar",
},
},
},
};
storiesOf("Components|Scrollbar", module)
.addDecorator(withReadme(Readme))
.addDecorator(withKnobs)
.add("base", () => (
<Section>
<Scrollbar
stype={select("stype", stypes, "mediumBlack")}
style={{ width: 300, height: 200 }}
>
================================================================ Lorem
ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim
id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.
================================================================
</Scrollbar>
</Section>
));
const Template = (args) => {
return (
<Scrollbar {...args}>
================================================================ Lorem
ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
est laborum.
================================================================
</Scrollbar>
);
};
export const Default = Template.bind({});
Default.args = {
stype: "mediumBlack",
style: { width: 300, height: 200 },
};

View File

@ -107,20 +107,30 @@ class SearchInput extends React.Component {
}
SearchInput.propTypes = {
/** Used as HTML `id` property */
id: PropTypes.string,
name: PropTypes.string,
/** Accepts class */
className: PropTypes.string,
/** Supported size of the input fields. */
size: PropTypes.oneOf(["base", "middle", "big", "huge"]),
/** Value of the input */
value: PropTypes.string,
/** Indicates the input field has scale */
scale: PropTypes.bool,
/** Placeholder text for the input */
placeholder: PropTypes.string,
/** Called with the new value. Required when input is not read only. Parent should pass it back as `value` */
onChange: PropTypes.func,
onClearSearch: PropTypes.func,
/** Indicates that the field cannot be used (e.g not authorized, or changes not saved) */
isDisabled: PropTypes.bool,
showClearButton: PropTypes.bool,
refreshTimeout: PropTypes.number,
autoRefresh: PropTypes.bool,
/** Child elements */
children: PropTypes.any,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

View File

@ -1,60 +1,45 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { StringValue } from "react-values";
import { withKnobs, boolean, text, select } from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import React, { useState } from "react";
import SearchInput from ".";
import Button from "../button";
import Section from "../../../.storybook/decorators/section";
const sizeOptions = ["base", "middle", "big", "huge"];
export default {
title: "Components/SearchInput",
component: SearchInput,
argTypes: {
onChange: { action: "onChange" },
},
};
class SearchStory extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "test1",
};
this.buttonClick = this.buttonClick.bind(this);
}
buttonClick() {
this.setState({ value: "test" });
}
render() {
return (
<Section>
<StringValue
onChange={(value) => {
action("onChange")(value);
}}
>
{({ value, set }) => (
<Section>
<div style={{ marginBottom: "20px" }}>
<Button label="Change props" onClick={this.buttonClick} />
</div>
<SearchInput
id={text("id", "")}
isDisabled={boolean("isDisabled", false)}
size={select("size", sizeOptions, "base")}
scale={boolean("scale", false)}
placeholder={text("placeholder", "Search")}
value={value}
onChange={(value) => {
set(value);
}}
/>
</Section>
)}
</StringValue>
</Section>
);
}
}
const Template = ({ value, onChange, ...args }) => {
const [valueBtn, setValue] = useState("test1");
const [searchValue, setSearchValue] = useState(value);
storiesOf("Components|Input", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("search", () => <SearchStory />);
const onButtonHandler = () => {
setValue("test");
};
return (
<>
<div style={{ marginBottom: "20px" }}>
<Button label="Change props" onClick={onButtonHandler} />
</div>
<SearchInput
{...args}
value={searchValue}
onChange={(value) => {
onChange(value);
setSearchValue(value);
}}
/>
</>
);
};
export const Default = Template.bind({});
Default.args = {
id: "",
isDisabled: false,
size: "base",
scale: false,
placeholder: "Search",
value: "",
};

View File

@ -1,80 +0,0 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import SelectedItem from ".";
import Section from "../../../.storybook/decorators/section";
import styled from "@emotion/styled";
function onClose(e) {
console.log("onClose", e);
}
const StyledContainer = styled.div`
padding: 0;
display: grid;
grid-gap: 10px;
`;
const StyledContainerInline = styled.div`
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
> * {
margin-right: 10px;
margin-bottom: 10px;
}
`;
storiesOf("Components|SelectedItem", module)
.addParameters({ options: { showAddonPanel: false } })
.add("all", () => {
return (
<Section>
<StyledContainerInline>
<SelectedItem
text="Selected item"
isInline={true}
onClose={onClose}
/>
<SelectedItem
text="Selected item"
isInline={true}
onClose={onClose}
/>
<SelectedItem
text="Selected item"
isInline={true}
onClose={onClose}
/>
<SelectedItem
text="Selected item"
isInline={true}
onClose={onClose}
/>
</StyledContainerInline>
<StyledContainer>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onClose}
/>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onClose}
/>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onClose}
/>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onClose}
/>
</StyledContainer>
</Section>
);
});

View File

@ -39,12 +39,19 @@ const SelectedItem = (props) => {
};
SelectedItem.propTypes = {
/** Selected item text */
text: PropTypes.string,
/** Sets the 'display: inline-block' property */
isInline: PropTypes.bool,
/** What the selected item will trigger when clicked */
onClose: PropTypes.func.isRequired,
/** Tells when the button should present a disabled state */
isDisabled: PropTypes.bool,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

View File

@ -1,27 +1,95 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { text, boolean, withKnobs } from "@storybook/addon-knobs/react";
import SelectedItem from ".";
import Section from "../../../.storybook/decorators/section";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import styled from "styled-components";
import SelectedItem from "./";
function onClose(e) {
console.log("onClose", e);
}
export default {
title: "Components/SelectedItem",
component: SelectedItem,
argTypes: {
onClose: { action: "onClose" },
},
};
const Template = ({ onClose, ...args }) => {
return <SelectedItem {...args} onClose={(e) => onClose(e)} />;
};
storiesOf("Components|SelectedItem", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("base", () => {
return (
<Section>
export const Default = Template.bind({});
Default.args = {
text: "Selected item",
isInline: true,
isDisabled: false,
};
const StyledContainer = styled.div`
padding: 0;
display: grid;
grid-gap: 10px;
`;
const StyledContainerInline = styled.div`
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
> * {
margin-right: 10px;
margin-bottom: 10px;
}
`;
const AllTemplate = ({ onClose, ...args }) => {
const onCloseHandler = (e) => {
onClose(e);
};
return (
<>
<StyledContainerInline>
<SelectedItem
text={text("text", "Selected item")}
isInline={boolean("isInline", true)}
onClose={onClose}
isDisabled={boolean("isDisabled", false)}
text="Selected item"
isInline={true}
onClose={onCloseHandler}
/>
</Section>
);
});
<SelectedItem
text="Selected item"
isInline={true}
onClose={onCloseHandler}
/>
<SelectedItem
text="Selected item"
isInline={true}
onClose={onCloseHandler}
/>
<SelectedItem
text="Selected item"
isInline={true}
onClose={onCloseHandler}
/>
</StyledContainerInline>
<StyledContainer>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onCloseHandler}
/>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onCloseHandler}
/>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onCloseHandler}
/>
<SelectedItem
text="Selected item"
isInline={false}
onClose={onCloseHandler}
/>
</StyledContainer>
</>
);
};
export const All = AllTemplate.bind({});

View File

@ -1,10 +1,9 @@
import React from "react";
import PropTypes from "prop-types";
import StyledButton from "./styled-selector-add-button"
import StyledButton from "./styled-selector-add-button";
import IconButton from "../icon-button";
const SelectorAddButton = (props) => {
const { isDisabled, title, className, id, style } = props;
@ -34,11 +33,17 @@ const SelectorAddButton = (props) => {
};
SelectorAddButton.propTypes = {
/** Title text */
title: PropTypes.string,
/** What the button will trigger when clicked */
onClick: PropTypes.func,
/** Tells when the button should present a disabled state */
isDisabled: PropTypes.bool,
/** Attribute className */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

View File

@ -1,25 +1,24 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { text, boolean, withKnobs } from "@storybook/addon-knobs/react";
import SelectorAddButton from ".";
import Section from "../../../.storybook/decorators/section";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import SelectorAddButton from "./";
storiesOf("Components|SelectorAddButton", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("base", () => {
const isDisabled = boolean("isDisabled", false);
return (
<Section>
<SelectorAddButton
isDisabled={isDisabled}
title={text("text", "Add item")}
onClick={(e) => {
!isDisabled && console.log("onClose", e);
}}
/>
</Section>
);
});
export default {
title: "Components/SelectorAddButton",
component: SelectorAddButton,
argTypes: { onClick: { action: "onClose" } },
};
const Template = ({ onClick, ...args }) => {
return (
<SelectorAddButton
onClick={(e) => {
!args.isDisabled && onClick(e);
}}
/>
);
};
export const Default = Template.bind({});
Default.args = {
isDisabled: false,
title: "Add item",
};

View File

@ -28,12 +28,19 @@ class SocialButton extends React.Component {
}
SocialButton.propTypes = {
/** Button text */
label: PropTypes.string,
/** Icon of button */
iconName: PropTypes.string,
/** Accepts tabindex prop*/
tabIndex: PropTypes.number,
/** Tells when the button should present a disabled state */
isDisabled: PropTypes.bool,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
};

View File

@ -1,33 +1,39 @@
import React from "react";
import { storiesOf } from "@storybook/react";
import { action } from "@storybook/addon-actions";
import { withKnobs, boolean, text, select } from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import SocialButton from ".";
import SocialButton from "./";
storiesOf("Components|Buttons|SocialButtons", module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add("social button", () => {
const socialNetworks = [
"static/images/share.google.react.svg",
"ShareFacebookIcon",
"ShareTwitterIcon",
"static/images/share.linkedin.react.svg",
];
const iconName = select(
"iconName",
["", ...socialNetworks],
"static/images/share.google.react.svg"
);
export default {
title: "Components/SocialButtons",
component: SocialButton,
parameters: {
docs: {
description: {
component: "Button is used for sign up with help social networks",
},
},
},
argTypes: {
onClick: { action: "onClick" },
iconName: {
control: {
type: "select",
options: [
"static/images/share.google.react.svg",
//"ShareFacebookIcon",
//"ShareTwitterIcon",
"static/images/share.linkedin.react.svg",
],
},
},
},
};
return (
<SocialButton
label={text("label", "Base SocialButton")}
iconName={iconName}
isDisabled={boolean("isDisabled", false)}
onClick={action("clicked")}
/>
);
});
const Template = ({ onClick, ...args }) => {
return <SocialButton {...args} onClick={() => onClick("clicked")} />;
};
export const Default = Template.bind({});
Default.args = {
label: "Base SocialButton",
iconName: "static/images/share.google.react.svg",
isDisabled: false,
};

View File

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": "true",
"homepage": "/products/files",
"title": "ONLYOFFICE",
"scripts": {
"start": "webpack-cli serve",
"build": "webpack --mode production",
@ -19,6 +20,7 @@
"@svgr/webpack": "^5.5.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^7.1.2",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^3.6.0",
"html-webpack-plugin": "4.5.0",

View File

@ -89,14 +89,14 @@
height: 36px;
}
</style>
<title>ONLYOFFICE</title>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div class="ipl-progress-indicator" id="ipl-progress-indicator"></div>
<div id="temp-content" style="display: none">
<div id="temp-content" style="display: none;">
<header class="temp-header-container">
<div id="burger-loader-svg" class="burger-loader-svg">
<svg
@ -111,7 +111,7 @@
ry="3"
width="24"
height="24"
style="fill: url('#fill0')"
style="fill: url('#fill0');"
></rect>
<defs>
<linearGradient id="fill0">
@ -137,7 +137,7 @@
ry="3"
width="168"
height="24"
style="fill: url('#fill01')"
style="fill: url('#fill01');"
></rect>
<defs>
<linearGradient id="fill01">
@ -165,7 +165,7 @@
r="18"
width="36"
height="36"
style="fill: url('#fill02')"
style="fill: url('#fill02');"
></circle>
<defs>
<linearGradient id="fill02">
@ -195,7 +195,7 @@
width="100%"
height="100%"
clip-path="url(#clip-path1)"
style="fill: url('#fill1')"
style="fill: url('#fill1');"
></rect>
<defs>
<clipPath id="clip-path1">
@ -225,7 +225,7 @@
width="100%"
height="100%"
clip-path="url(#clip-path2)"
style="fill: url('#fill2')"
style="fill: url('#fill2');"
></rect>
<defs>
<clipPath id="clip-path2">

View File

@ -52,7 +52,8 @@ class DeleteDialogComponent extends React.Component {
deleteSelectedElem: t("DeleteSelectedElem"),
};
deleteAction(translations);
deleteAction(translations)
.catch((err) => toastr.error(err));
};
onChange = (event) => {

View File

@ -135,6 +135,7 @@ class DownloadDialogComponent extends React.Component {
const {
//onDownloadProgress,
t,
getDownloadProgress,
setSecondaryProgressBarData,
clearSecondaryProgressData,
} = this.props;
@ -154,7 +155,8 @@ class DownloadDialogComponent extends React.Component {
downloadFormatFiles(fileConvertIds, folderIds)
.then((res) => {
this.onClose();
this.props.getDownloadProgress(res[0], t("ArchivingData"));
getDownloadProgress(res[0], t("ArchivingData"))
.catch((err) => toastr.error(err));
})
.catch((err) => {
setSecondaryProgressBarData({

View File

@ -9,7 +9,7 @@ import DragAndDrop from "@appserver/components/drag-and-drop";
import Row from "@appserver/components/row";
import FilesRowContent from "./FilesRowContent";
import history from "@appserver/common/history";
import toastr from "@appserver/components/toast";
import toastr from "studio/toastr";
import { FileAction } from "@appserver/common/constants";
const StyledSimpleFilesRow = styled(Row)`
@ -81,6 +81,7 @@ const SimpleFilesRow = (props) => {
homepage,
isTabletView,
actionId,
selectedFolderId,
setSharingPanelVisible,
setChangeOwnerPanelVisible,
@ -103,6 +104,8 @@ const SimpleFilesRow = (props) => {
selectRowAction,
setThirdpartyInfo,
setMediaViewerData,
setDragging,
startUpload,
} = props;
const {
@ -111,7 +114,6 @@ const SimpleFilesRow = (props) => {
fileExst,
shared,
access,
value,
contextOptions,
icon,
providerKey,
@ -122,6 +124,9 @@ const SimpleFilesRow = (props) => {
locked,
} = item;
let value = fileExst ? `file_${id}` : `folder_${id}`;
value += draggable ? "_draggable" : "";
const isThirdPartyFolder = providerKey && isRootFolder;
const onContentRowSelect = (checked, file) => {
@ -191,14 +196,22 @@ const SimpleFilesRow = (props) => {
}
};
const finalizeVersion = () => finalizeVersionAction(id);
const finalizeVersion = () =>
finalizeVersionAction(id).catch((err) => toastr.error(err));
const onClickFavorite = (e) => {
const { action } = e.currentTarget.dataset;
setFavoriteAction(action, id);
setFavoriteAction(action, id)
.then(() =>
action === "mark"
? toastr.success(t("MarkedAsFavorite"))
: toastr.success(t("RemovedFromFavorites"))
)
.catch((err) => toastr.error(err));
};
const lockFile = () => lockFileAction(id, locked);
const lockFile = () =>
lockFileAction(id, locked).catch((err) => toastr.error(err));
const onClickLinkForPortal = () => {
const isFile = !!fileExst;
@ -218,7 +231,8 @@ const SimpleFilesRow = (props) => {
const onClickDownload = () => window.open(viewUrl, "_blank");
const onDuplicate = () => duplicateAction(item, t("CopyOperation"));
const onDuplicate = () =>
duplicateAction(item, t("CopyOperation")).catch((err) => toastr.error(err));
const onClickRename = () => {
setAction({
@ -245,204 +259,218 @@ const SimpleFilesRow = (props) => {
const translations = {
deleteOperation: t("DeleteOperation"),
folderRemoved: t("FolderRemoved"),
fileRemoved: t("FileRemoved"),
};
item.fileExst
? deleteFileAction(item.id, item.folderId, translations)
: deleteFolderAction(item.id, item.parentId, translations);
.then(() => toastr.success(t("FileRemoved")))
.catch((err) => toastr.error(err))
: deleteFolderAction(item.id, item.parentId, translations)
.then(() => toastr.success(t("FolderRemoved")))
.catch((err) => toastr.error(err));
};
const getFilesContextOptions = useCallback(
(options, item) => {
const isSharable = item.access !== 1 && item.access !== 0;
const getFilesContextOptions = useCallback(() => {
const isSharable = item.access !== 1 && item.access !== 0;
return options.map((option) => {
switch (option) {
case "open":
return {
key: option,
label: t("Open"),
icon: "CatalogFolderIcon",
onClick: onOpenLocation,
disabled: false,
};
case "show-version-history":
return {
key: option,
label: t("ShowVersionHistory"),
icon: "HistoryIcon",
onClick: showVersionHistory,
disabled: false,
};
case "finalize-version":
return {
key: option,
label: t("FinalizeVersion"),
icon: "HistoryFinalizedIcon",
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: "DownloadAsIcon",
onClick: onOpenLocation,
disabled: false,
};
case "mark-as-favorite":
return {
key: option,
label: t("MarkAsFavorite"),
icon: "FavoritesIcon",
onClick: onClickFavorite,
disabled: false,
"data-action": "mark",
};
case "block-unblock-version":
return {
key: option,
label: t("UnblockVersion"),
icon: "LockIcon",
onClick: lockFile,
disabled: false,
};
case "sharing-settings":
return {
key: option,
label: t("SharingSettings"),
icon: "CatalogSharedIcon",
onClick: onClickShare,
disabled: isSharable,
};
case "send-by-email":
return {
key: option,
label: t("SendByEmail"),
icon: "MailIcon",
disabled: true,
};
case "owner-change":
return {
key: option,
label: t("ChangeOwner"),
icon: "CatalogUserIcon",
onClick: onOwnerChange,
disabled: false,
};
case "link-for-portal-users":
return {
key: option,
label: t("LinkForPortalUsers"),
icon: "InvitationLinkIcon",
onClick: onClickLinkForPortal,
disabled: false,
};
case "edit":
return {
key: option,
label: t("Edit"),
icon: "AccessEditIcon",
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: "EyeIcon",
onClick: onMediaFileClick,
disabled: false,
};
case "download":
return {
key: option,
label: t("Download"),
icon: "DownloadIcon",
onClick: onClickDownload,
disabled: false,
};
case "move":
return {
key: option,
label: t("MoveTo"),
icon: "MoveToIcon",
onClick: onMoveAction,
disabled: false,
};
case "copy":
return {
key: option,
label: t("Copy"),
icon: "CopyIcon",
onClick: onCopyAction,
disabled: false,
};
case "duplicate":
return {
key: option,
label: t("Duplicate"),
icon: "CopyIcon",
onClick: onDuplicate,
disabled: false,
};
case "rename":
return {
key: option,
label: t("Rename"),
icon: "RenameIcon",
onClick: onClickRename,
disabled: false,
};
case "change-thirdparty-info":
return {
key: option,
label: t("ThirdPartyInfo"),
icon: "AccessEditIcon",
onClick: onChangeThirdPartyInfo,
disabled: false,
};
case "delete":
return {
key: option,
label: isThirdPartyFolder ? t("DeleteThirdParty") : t("Delete"),
icon: "CatalogTrashIcon",
onClick: onClickDelete,
disabled: false,
};
case "remove-from-favorites":
return {
key: option,
label: t("RemoveFromFavorites"),
icon: "FavoritesIcon",
onClick: onClickFavorite,
disabled: false,
"data-action": "remove",
};
default:
break;
}
return contextOptions.map((option) => {
switch (option) {
case "open":
return {
key: option,
label: t("Open"),
icon: "CatalogFolderIcon",
onClick: onOpenLocation,
disabled: false,
};
case "show-version-history":
return {
key: option,
label: t("ShowVersionHistory"),
icon: "HistoryIcon",
onClick: showVersionHistory,
disabled: false,
};
case "finalize-version":
return {
key: option,
label: t("FinalizeVersion"),
icon: "HistoryFinalizedIcon",
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: "DownloadAsIcon",
onClick: onOpenLocation,
disabled: false,
};
case "mark-as-favorite":
return {
key: option,
label: t("MarkAsFavorite"),
icon: "FavoritesIcon",
onClick: onClickFavorite,
disabled: false,
"data-action": "mark",
};
case "block-unblock-version":
return {
key: option,
label: t("UnblockVersion"),
icon: "LockIcon",
onClick: lockFile,
disabled: false,
};
case "sharing-settings":
return {
key: option,
label: t("SharingSettings"),
icon: "CatalogSharedIcon",
onClick: onClickShare,
disabled: isSharable,
};
case "send-by-email":
return {
key: option,
label: t("SendByEmail"),
icon: "MailIcon",
disabled: true,
};
case "owner-change":
return {
key: option,
label: t("ChangeOwner"),
icon: "CatalogUserIcon",
onClick: onOwnerChange,
disabled: false,
};
case "link-for-portal-users":
return {
key: option,
label: t("LinkForPortalUsers"),
icon: "InvitationLinkIcon",
onClick: onClickLinkForPortal,
disabled: false,
};
case "edit":
return {
key: option,
label: t("Edit"),
icon: "AccessEditIcon",
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: "EyeIcon",
onClick: onMediaFileClick,
disabled: false,
};
case "download":
return {
key: option,
label: t("Download"),
icon: "DownloadIcon",
onClick: onClickDownload,
disabled: false,
};
case "move":
return {
key: option,
label: t("MoveTo"),
icon: "MoveToIcon",
onClick: onMoveAction,
disabled: false,
};
case "copy":
return {
key: option,
label: t("Copy"),
icon: "CopyIcon",
onClick: onCopyAction,
disabled: false,
};
case "duplicate":
return {
key: option,
label: t("Duplicate"),
icon: "CopyIcon",
onClick: onDuplicate,
disabled: false,
};
case "rename":
return {
key: option,
label: t("Rename"),
icon: "RenameIcon",
onClick: onClickRename,
disabled: false,
};
case "change-thirdparty-info":
return {
key: option,
label: t("ThirdPartyInfo"),
icon: "AccessEditIcon",
onClick: onChangeThirdPartyInfo,
disabled: false,
};
case "delete":
return {
key: option,
label: isThirdPartyFolder ? t("DeleteThirdParty") : t("Delete"),
icon: "CatalogTrashIcon",
onClick: onClickDelete,
disabled: false,
};
case "remove-from-favorites":
return {
key: option,
label: t("RemoveFromFavorites"),
icon: "FavoritesIcon",
onClick: onClickFavorite,
disabled: false,
"data-action": "remove",
};
default:
break;
}
return undefined;
});
},
[contextOptions, item]
);
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, item.id);
} else {
onDropZoneUpload(items, selectedFolderId);
}
};
// const onSelectItem = () => {
// selected === "close" && setSelected("none");
@ -457,28 +485,25 @@ const SimpleFilesRow = (props) => {
const contextOptionsProps =
!isEdit && contextOptions && contextOptions.length > 0
? {
contextOptions: getFilesContextOptions(contextOptions, item),
contextOptions: getFilesContextOptions(),
}
: {};
const checkedProps = isEdit || id <= 0 ? {} : { checked };
const element = getItemIcon(isEdit || id <= 0);
const displayShareButton = isMobile ? "26px" : !canShare ? "38px" : "96px";
let className = isFolder && access < 2 && !isRecycleBin ? " dropable" : "";
if (draggable) className += " draggable";
const sharedButton =
!canShare || (isPrivacy && !fileExst) || isEdit || id <= 0 || isMobile
? null
: getSharedButton(shared);
const displayShareButton = isMobile ? "26px" : !canShare ? "38px" : "96px";
let className = isFolder && access < 2 && !isRecycleBin ? " dropable" : "";
if (draggable) className += " draggable";
return (
<DragAndDrop
className={className}
//onDrop={this.onDrop.bind(this, item)}
onDrop={onDrop}
//onMouseDown={this.onMouseDown}
dragging={dragging && isFolder && access < 2}
{...contextOptionsProps}
@ -517,11 +542,12 @@ export default inject(
versionHistoryStore,
filesActionsStore,
mediaViewerDataStore,
uploadDataStore,
},
{ item }
) => {
const { homepage, isTabletView } = auth.settingsStore;
const { dragging, setIsLoading } = initFilesStore;
const { dragging, setDragging, setIsLoading } = initFilesStore;
const { type, extension, id } = filesStore.fileActionStore;
const { isRecycleBinFolder, isPrivacyFolder } = treeFoldersStore;
@ -544,7 +570,7 @@ export default inject(
fileActionStore,
} = filesStore;
const { isRootFolder } = selectedFolderStore;
const { isRootFolder, id: selectedFolderId } = selectedFolderStore;
const { setIsVerHistoryPanel, setVerHistoryFileId } = versionHistoryStore;
const { setAction } = fileActionStore;
@ -554,7 +580,7 @@ export default inject(
const isFolder = selectedItem ? false : item.fileExst ? false : true;
const draggable =
selectedItem && isRecycleBinFolder && selectedItem.id !== id;
!isRecycleBinFolder && selectedItem && selectedItem.id !== id;
const {
deleteFileAction,
@ -569,6 +595,7 @@ export default inject(
} = filesActionsStore;
const { setMediaViewerData } = mediaViewerDataStore;
const { startUpload } = uploadDataStore;
return {
dragging,
@ -584,6 +611,7 @@ export default inject(
checked: selection.some((el) => el.id === item.id),
isFolder,
draggable,
isItemsSelected: !!selection.length,
homepage,
isTabletView,
actionId: fileActionStore.id,
@ -608,16 +636,9 @@ export default inject(
selectRowAction,
setThirdpartyInfo,
setMediaViewerData,
selectedFolderId,
setDragging,
startUpload,
};
}
)(withTranslation("Home")(observer(SimpleFilesRow)));
// onDrop = (item, items, e) => {
// const { onDropZoneUpload, selectedFolderId } = this.props;
// if (!item.fileExst) {
// onDropZoneUpload(items, item.id);
// } else {
// onDropZoneUpload(items, selectedFolderId);
// }
// };

View File

@ -44,13 +44,13 @@ class SectionBodyContent extends React.Component {
constructor(props) {
super(props);
this.state = {
isDrag: false,
canDrag: true,
};
// this.state = {
// isDrag: false,
// canDrag: true,
// };
this.tooltipRef = React.createRef();
this.currentDroppable = null;
// this.tooltipRef = React.createRef();
// this.currentDroppable = null;
}
componentDidMount() {
@ -58,22 +58,20 @@ class SectionBodyContent extends React.Component {
"#customScrollBar > .scroll-body"
);
window.addEventListener("mouseup", this.onMouseUp);
document.addEventListener("dragstart", this.onDragStart);
document.addEventListener("dragover", this.onDragOver);
document.addEventListener("dragleave", this.onDragLeaveDoc);
document.addEventListener("drop", this.onDropEvent);
// window.addEventListener("mouseup", this.onMouseUp);
// document.addEventListener("dragstart", this.onDragStart);
// document.addEventListener("dragover", this.onDragOver);
// document.addEventListener("dragleave", this.onDragLeaveDoc);
// document.addEventListener("drop", this.onDropEvent);
}
componentWillUnmount() {
window.removeEventListener("mouseup", this.onMouseUp);
document.addEventListener("dragstart", this.onDragStart);
document.removeEventListener("dragover", this.onDragOver);
document.removeEventListener("dragleave", this.onDragLeaveDoc);
document.removeEventListener("drop", this.onDropEvent);
}
// componentWillUnmount() {
// window.removeEventListener("mouseup", this.onMouseUp);
// document.addEventListener("dragstart", this.onDragStart);
// document.removeEventListener("dragover", this.onDragOver);
// document.removeEventListener("dragleave", this.onDragLeaveDoc);
// document.removeEventListener("drop", this.onDropEvent);
// }
componentDidUpdate(prevProps, prevState) {
Object.entries(this.props).forEach(
@ -98,250 +96,250 @@ class SectionBodyContent extends React.Component {
}
}
onDragStart = (e) => {
if (e.dataTransfer.dropEffect === "none") {
this.state.canDrag && this.setState({ canDrag: false });
}
};
// onDragStart = (e) => {
// if (e.dataTransfer.dropEffect === "none") {
// this.state.canDrag && this.setState({ canDrag: false });
// }
// };
onDropEvent = () => {
this.props.dragging && this.props.setDragging(false);
};
// onDropEvent = () => {
// this.props.dragging && this.props.setDragging(false);
// };
onDragOver = (e) => {
e.preventDefault();
const { dragging, setDragging } = this.props;
if (e.dataTransfer.items.length > 0 && !dragging && this.state.canDrag) {
setDragging(true);
}
};
// onDragOver = (e) => {
// e.preventDefault();
// const { dragging, setDragging } = this.props;
// if (e.dataTransfer.items.length > 0 && !dragging && this.state.canDrag) {
// setDragging(true);
// }
// };
onDragLeaveDoc = (e) => {
e.preventDefault();
const { dragging, setDragging } = this.props;
if (dragging && !e.relatedTarget) {
setDragging(false);
}
};
// onDragLeaveDoc = (e) => {
// e.preventDefault();
// const { dragging, setDragging } = this.props;
// if (dragging && !e.relatedTarget) {
// setDragging(false);
// }
// };
onMouseDown = (e) => {
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;
}
document.addEventListener("mousemove", this.onMouseMove);
this.setTooltipPosition(e);
const { selection } = this.props;
// onMouseDown = (e) => {
// 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;
// }
// document.addEventListener("mousemove", this.onMouseMove);
// this.setTooltipPosition(e);
// const { selection } = this.props;
const elem = e.currentTarget.closest(".draggable");
if (!elem) {
return;
}
const value = elem.getAttribute("value");
if (!value) {
return;
}
let splitValue = value.split("_");
let item = null;
if (splitValue[0] === "folder") {
splitValue.splice(0, 1);
if (splitValue[splitValue.length - 1] === "draggable") {
splitValue.splice(-1, 1);
}
splitValue = splitValue.join("_");
// const elem = e.currentTarget.closest(".draggable");
// if (!elem) {
// return;
// }
// const value = elem.getAttribute("value");
// if (!value) {
// return;
// }
// let splitValue = value.split("_");
// let item = null;
// if (splitValue[0] === "folder") {
// splitValue.splice(0, 1);
// if (splitValue[splitValue.length - 1] === "draggable") {
// splitValue.splice(-1, 1);
// }
// splitValue = splitValue.join("_");
item = selection.find((x) => x.id + "" === splitValue && !x.fileExst);
} else {
splitValue.splice(0, 1);
if (splitValue[splitValue.length - 1] === "draggable") {
splitValue.splice(-1, 1);
}
splitValue = splitValue.join("_");
// item = selection.find((x) => x.id + "" === splitValue && !x.fileExst);
// } else {
// splitValue.splice(0, 1);
// if (splitValue[splitValue.length - 1] === "draggable") {
// splitValue.splice(-1, 1);
// }
// splitValue = splitValue.join("_");
item = selection.find((x) => x.id + "" === splitValue && x.fileExst);
}
if (item) {
this.setState({ isDrag: true });
}
};
// item = selection.find((x) => x.id + "" === splitValue && x.fileExst);
// }
// if (item) {
// this.setState({ isDrag: true });
// }
// };
onMouseUp = (e) => {
const { selection, dragging, setDragging, dragItem } = this.props;
// onMouseUp = (e) => {
// const { selection, dragging, setDragging, dragItem } = this.props;
document.body.classList.remove("drag-cursor");
// document.body.classList.remove("drag-cursor");
if (this.state.isDrag || !this.state.canDrag) {
this.setState({ isDrag: false, canDrag: true });
}
const mouseButton = e.which
? e.which !== 1
: e.button
? e.button !== 0
: false;
if (mouseButton || !this.tooltipRef.current || !dragging) {
return;
}
document.removeEventListener("mousemove", this.onMouseMove);
this.tooltipRef.current.style.display = "none";
// if (this.state.isDrag || !this.state.canDrag) {
// this.setState({ isDrag: false, canDrag: true });
// }
// const mouseButton = e.which
// ? e.which !== 1
// : e.button
// ? e.button !== 0
// : false;
// if (mouseButton || !this.tooltipRef.current || !dragging) {
// return;
// }
// document.removeEventListener("mousemove", this.onMouseMove);
// this.tooltipRef.current.style.display = "none";
const elem = e.target.closest(".dropable");
if (elem && selection.length && dragging) {
const value = elem.getAttribute("value");
if (!value) {
setDragging(false);
return;
}
let splitValue = value.split("_");
let item = null;
if (splitValue[0] === "folder") {
splitValue.splice(0, 1);
if (splitValue[splitValue.length - 1] === "draggable") {
splitValue.splice(-1, 1);
}
splitValue = splitValue.join("_");
// const elem = e.target.closest(".dropable");
// if (elem && selection.length && dragging) {
// const value = elem.getAttribute("value");
// if (!value) {
// setDragging(false);
// return;
// }
// let splitValue = value.split("_");
// let item = null;
// if (splitValue[0] === "folder") {
// splitValue.splice(0, 1);
// if (splitValue[splitValue.length - 1] === "draggable") {
// splitValue.splice(-1, 1);
// }
// splitValue = splitValue.join("_");
item = selection.find((x) => x.id + "" === splitValue && !x.fileExst);
} else {
return;
}
if (item) {
setDragging(false);
return;
} else {
setDragging(false);
this.onMoveTo(splitValue);
return;
}
} else {
setDragging(false);
if (dragItem) {
this.onMoveTo(dragItem);
return;
}
return;
}
};
// item = selection.find((x) => x.id + "" === splitValue && !x.fileExst);
// } else {
// return;
// }
// if (item) {
// setDragging(false);
// return;
// } else {
// setDragging(false);
// this.onMoveTo(splitValue);
// return;
// }
// } else {
// setDragging(false);
// if (dragItem) {
// this.onMoveTo(dragItem);
// return;
// }
// return;
// }
// };
onMouseMove = (e) => {
if (this.state.isDrag) {
document.body.classList.add("drag-cursor");
!this.props.dragging && this.props.setDragging(true);
const tooltip = this.tooltipRef.current;
tooltip.style.display = "block";
this.setTooltipPosition(e);
// onMouseMove = (e) => {
// if (this.state.isDrag) {
// document.body.classList.add("drag-cursor");
// !this.props.dragging && this.props.setDragging(true);
// const tooltip = this.tooltipRef.current;
// tooltip.style.display = "block";
// this.setTooltipPosition(e);
const wrapperElement = document.elementFromPoint(e.clientX, e.clientY);
if (!wrapperElement) {
return;
}
const droppable = wrapperElement.closest(".dropable");
// const wrapperElement = document.elementFromPoint(e.clientX, e.clientY);
// if (!wrapperElement) {
// return;
// }
// const droppable = wrapperElement.closest(".dropable");
if (this.currentDroppable !== droppable) {
if (this.currentDroppable) {
this.currentDroppable.style.background = backgroundDragEnterColor;
}
this.currentDroppable = droppable;
// if (this.currentDroppable !== droppable) {
// if (this.currentDroppable) {
// this.currentDroppable.style.background = backgroundDragEnterColor;
// }
// this.currentDroppable = droppable;
if (this.currentDroppable) {
droppable.style.background = backgroundDragColor;
this.currentDroppable = droppable;
}
}
}
};
// if (this.currentDroppable) {
// droppable.style.background = backgroundDragColor;
// this.currentDroppable = droppable;
// }
// }
// }
// };
setTooltipPosition = (e) => {
const tooltip = this.tooltipRef.current;
if (tooltip) {
const margin = 8;
tooltip.style.left = e.pageX + margin + "px";
tooltip.style.top = e.pageY + margin + "px";
}
};
// setTooltipPosition = (e) => {
// const tooltip = this.tooltipRef.current;
// if (tooltip) {
// const margin = 8;
// tooltip.style.left = e.pageX + margin + "px";
// tooltip.style.top = e.pageY + margin + "px";
// }
// };
onMoveTo = (destFolderId) => {
const {
selection,
t,
isShare,
isCommon,
isAdmin,
setSecondaryProgressBarData,
copyToAction,
moveToAction,
} = this.props;
// onMoveTo = (destFolderId) => {
// const {
// selection,
// t,
// isShare,
// isCommon,
// isAdmin,
// setSecondaryProgressBarData,
// copyToAction,
// moveToAction,
// } = this.props;
const folderIds = [];
const fileIds = [];
const conflictResolveType = 0; //Skip = 0, Overwrite = 1, Duplicate = 2
const deleteAfter = true;
// const folderIds = [];
// const fileIds = [];
// const conflictResolveType = 0; //Skip = 0, Overwrite = 1, Duplicate = 2
// const deleteAfter = true;
setSecondaryProgressBarData({
icon: "move",
visible: true,
percent: 0,
label: t("MoveToOperation"),
alert: false,
});
// setSecondaryProgressBarData({
// icon: "move",
// visible: true,
// percent: 0,
// label: t("MoveToOperation"),
// alert: false,
// });
for (let item of selection) {
if (item.fileExst) {
fileIds.push(item.id);
} else {
folderIds.push(item.id);
}
}
// for (let item of selection) {
// if (item.fileExst) {
// fileIds.push(item.id);
// } else {
// folderIds.push(item.id);
// }
// }
if (isAdmin) {
if (isShare) {
copyToAction(
destFolderId,
folderIds,
fileIds,
conflictResolveType,
deleteAfter
);
} else {
moveToAction(
destFolderId,
folderIds,
fileIds,
conflictResolveType,
deleteAfter
);
}
} else {
if (isShare || isCommon) {
copyToAction(
destFolderId,
folderIds,
fileIds,
conflictResolveType,
deleteAfter
);
} else {
moveToAction(
destFolderId,
folderIds,
fileIds,
conflictResolveType,
deleteAfter
);
}
}
};
// if (isAdmin) {
// if (isShare) {
// copyToAction(
// destFolderId,
// folderIds,
// fileIds,
// conflictResolveType,
// deleteAfter
// );
// } else {
// moveToAction(
// destFolderId,
// folderIds,
// fileIds,
// conflictResolveType,
// deleteAfter
// );
// }
// } else {
// if (isShare || isCommon) {
// copyToAction(
// destFolderId,
// folderIds,
// fileIds,
// conflictResolveType,
// deleteAfter
// );
// } else {
// moveToAction(
// destFolderId,
// folderIds,
// fileIds,
// conflictResolveType,
// deleteAfter
// );
// }
// }
// };
renderFileMoveTooltip = () => {
const { selection, iconOfDraggedFile } = this.props;
@ -375,15 +373,15 @@ class SectionBodyContent extends React.Component {
);
};
startMoveOperation = () => {
this.props.moveToAction(this.props.dragItem);
this.onCloseThirdPartyMoveDialog();
};
// startMoveOperation = () => {
// this.props.moveToAction(this.props.dragItem);
// this.onCloseThirdPartyMoveDialog();
// };
startCopyOperation = () => {
this.props.copyToAction(this.props.dragItem);
this.onCloseThirdPartyMoveDialog();
};
// startCopyOperation = () => {
// this.props.copyToAction(this.props.dragItem);
// this.onCloseThirdPartyMoveDialog();
// };
render() {
//console.log("Files Home SectionBodyContent render", this.props);

View File

@ -215,7 +215,11 @@ class SectionHeaderContent extends React.Component {
onMoveAction = () => this.props.setMoveToPanelVisible(true);
onCopyAction = () => this.props.setCopyPanelVisible(true);
downloadAction = () => this.props.downloadAction(t("ArchivingData"));
downloadAction = () =>
this.props
.downloadAction(this.props.t("ArchivingData"))
.catch((err) => toastr.error(err));
downloadAsAction = () => this.props.setDownloadDialogVisible(true);
renameAction = () => toastr.info("renameAction click");
onOpenSharingPanel = () => this.props.setSharingPanelVisible(true);
@ -237,7 +241,7 @@ class SectionHeaderContent extends React.Component {
deleteSelectedElem: t("DeleteSelectedElem"),
};
deleteAction(translations);
deleteAction(translations).catch((err) => toastr.error(err));
}
};
@ -555,7 +559,6 @@ export default inject(
auth,
initFilesStore,
filesStore,
uploadDataStore,
dialogsStore,
treeFoldersStore,
selectedFolderStore,
@ -563,7 +566,6 @@ export default inject(
settingsStore,
}) => {
const { setIsLoading } = initFilesStore;
const { secondaryProgressDataStore } = uploadDataStore;
const {
setSelected,
fileActionStore,

View File

@ -274,11 +274,7 @@ class PureHome extends React.Component {
</PageLayout.SectionFilter>
<PageLayout.SectionBody>
<SectionBodyContent
isMobile={isMobile}
onChange={this.onRowChange}
onDropZoneUpload={this.onDrop}
/>
<SectionBodyContent />
</PageLayout.SectionBody>
<PageLayout.SectionPaging>
@ -319,7 +315,6 @@ export default inject(
filter,
fileActionStore,
selection,
setSelections,
} = filesStore;

View File

@ -22,8 +22,6 @@ import { FileAction } from "@appserver/common/constants";
import { TIMEOUT } from "../helpers/constants";
import { loopTreeFolders } from "../helpers/files-helpers";
//import toastr from "@appserver/components/toast";
const {
fetchFiles,
markItemAsFavorite,
@ -77,7 +75,7 @@ class FilesActionStore {
alert: false,
});
removeFiles(folderIds, fileIds, deleteAfter, immediately)
return removeFiles(folderIds, fileIds, deleteAfter, immediately)
.then((res) => {
const id = res[0] && res[0].id ? res[0].id : null;
this.loopDeleteOperation(id, translations);
@ -87,7 +85,6 @@ class FilesActionStore {
visible: true,
alert: true,
});
//toastr.error(err);
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
}
@ -130,7 +127,6 @@ class FilesActionStore {
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
setTreeFolders(newTreeFolders);
}
//toastr.success(successMessage);
});
}
})
@ -139,7 +135,6 @@ class FilesActionStore {
visible: true,
alert: true,
});
//toastr.error(err);
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
};
@ -147,7 +142,7 @@ class FilesActionStore {
getDownloadProgress = (data, label) => {
const url = data.url;
getProgress()
return getProgress()
.then((res) => {
const currentItem = res.find((x) => x.id === data.id);
if (!url) {
@ -169,7 +164,6 @@ class FilesActionStore {
visible: true,
alert: true,
});
//toastr.error(err);
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
};
@ -180,8 +174,9 @@ class FilesActionStore {
const folderIds = [];
const items = [];
if (selection.length === 1) {
return window.open(selection[0].viewUrl, "_blank");
if (selection.length === 1 && selection[0].fileExst) {
window.open(selection[0].viewUrl, "_blank");
return Promise.resolve();
}
for (let item of selection) {
@ -202,7 +197,7 @@ class FilesActionStore {
alert: false,
});
downloadFiles(fileIds, folderIds)
return downloadFiles(fileIds, folderIds)
.then((res) => {
this.getDownloadProgress(res[0], label);
})
@ -211,7 +206,6 @@ class FilesActionStore {
visible: true,
alert: true,
});
//toastr.error(err);
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
};
@ -263,7 +257,7 @@ class FilesActionStore {
conflictResolveType,
deleteAfter
) => {
copyToFolder(
return copyToFolder(
destFolderId,
folderIds,
fileIds,
@ -320,7 +314,7 @@ class FilesActionStore {
label: translations.deleteOperation,
alert: false,
});
deleteFile(fileId)
return deleteFile(fileId)
.then((res) => {
const id = res[0] && res[0].id ? res[0].id : null;
this.loopDeleteProgress(id, currentFolderId, false, translations);
@ -330,7 +324,6 @@ class FilesActionStore {
visible: true,
alert: true,
});
//toastr.error(err);
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
};
@ -343,7 +336,7 @@ class FilesActionStore {
label: translations.deleteOperation,
alert: false,
});
deleteFolder(folderId, currentFolderId)
return deleteFolder(folderId, currentFolderId)
.then((res) => {
const id = res[0] && res[0].id ? res[0].id : null;
this.loopDeleteProgress(id, currentFolderId, true, translations);
@ -353,7 +346,6 @@ class FilesActionStore {
visible: true,
alert: true,
});
//toastr.error(err);
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
});
};
@ -394,16 +386,12 @@ class FilesActionStore {
loopTreeFolders(path, newTreeFolders, folders, foldersCount);
setTreeFolders(newTreeFolders);
}
//isFolder
// ? toastr.success(translations.folderRemoved)
// : toastr.success(translations.fileRemoved);
})
.catch((err) => {
setSecondaryProgressBarData({
visible: true,
alert: true,
});
//toastr.error(err);
setTimeout(() => clearSecondaryProgressData(), TIMEOUT);
})
.finally(() =>
@ -415,22 +403,22 @@ class FilesActionStore {
lockFileAction = (id, locked) => {
setIsLoading(true);
lockFile(id, locked).then((res) => {
return lockFile(id, locked).then((res) => {
/*const newFiles = files;
const indexOfFile = newFiles.findIndex(x => x.id === res.id);
newFiles[indexOfFile] = res;*/
fetchFiles(selectedFolderStore.id, filesStore.filter)
//.catch((err) => toastr.error(err))
.finally(() => setIsLoading(false));
fetchFiles(selectedFolderStore.id, filesStore.filter).finally(() =>
setIsLoading(false)
);
});
};
finalizeVersionAction = (id) => {
setIsLoading(true);
finalizeVersion(id, 0, false)
return finalizeVersion(id, 0, false)
.then(() => {
return fetchFiles(selectedFolderStore.id, filesStore.filter); //.catch((err) => toastr.error(err));
fetchFiles(selectedFolderStore.id, filesStore.filter);
})
.finally(() => setIsLoading(false));
};
@ -450,8 +438,8 @@ class FilesActionStore {
alert: false,
});
this.copyToAction(
selectedFolderId,
return this.copyToAction(
selectedFolderStore.id,
folderIds,
fileIds,
conflictResolveType,
@ -464,20 +452,15 @@ class FilesActionStore {
switch (action) {
case "mark":
return markItemAsFavorite([id]).then(() => getFileInfo(id));
//.then(() => toastr.success(t("MarkedAsFavorite")))
//.catch((e) => toastr.error(e));
case "remove":
return (
removeItemFromFavorite([id])
.then(() => {
return treeFoldersStore.isFavoritesFolder
? fetchFavoritesFolder(selectedFolderId)
: getFileInfo(id);
})
//.then(() => toastr.success(t("RemovedFromFavorites")))
.then(() => setSelected("close"))
);
//.catch((e) => toastr.error(e));
return removeItemFromFavorite([id])
.then(() => {
return treeFoldersStore.isFavoritesFolder
? fetchFavoritesFolder(selectedFolderStore.id)
: getFileInfo(id);
})
.then(() => setSelected("close"));
default:
return;
}

View File

@ -636,9 +636,6 @@ class FilesStore {
const contextOptions = this.getFilesContextOptions(item, canOpenPlayer);
//let value = fileExst ? `file_${id}` : `folder_${id}`;
//value += draggable ? "_draggable" : "";
//const isCanWebEdit = canWebEdit(item.fileExst);
const icon = getIcon(24, fileExst, providerKey);
@ -669,13 +666,11 @@ class FilesStore {
title,
updated,
updatedBy,
//value,
version,
versionGroup,
viewUrl,
webUrl,
providerKey,
//draggable,
canOpenPlayer,
//canWebEdit: isCanWebEdit,
//canShare,
@ -836,6 +831,7 @@ class FilesStore {
};
setSelections = (items) => {
if (!items.length) return;
if (this.selection.length > items.length) {
//Delete selection
const newSelection = [];

View File

@ -3,10 +3,14 @@ const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const TerserPlugin = require("terser-webpack-plugin");
//const CompressionPlugin = require("compression-webpack-plugin");
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies;
const homepage = pkg.homepage;
const title = pkg.title;
var config = {
mode: "development",
@ -15,7 +19,7 @@ var config = {
devServer: {
publicPath: homepage,
contentBase: [path.join(__dirname, "public")],
contentBase: [path.join(__dirname, "dist")],
contentBasePublicPath: homepage,
port: 5008,
historyApiFallback: {
@ -41,9 +45,11 @@ var config = {
},
output: {
publicPath: "auto", //homepage
chunkFilename: "[id].[contenthash].js",
publicPath: "auto",
chunkFilename: "js/[id].[contenthash].js",
assetModuleFilename: "assets/[hash][ext][query]",
path: path.resolve(process.cwd(), "dist"),
filename: "[name].[contenthash].bundle.js",
},
resolve: {
@ -55,6 +61,10 @@ var config = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
type: "asset/resource",
},
{
test: /\.m?js/,
type: "javascript/auto",
@ -139,6 +149,7 @@ var config = {
new HtmlWebpackPlugin({
template: "./public/index.html",
publicPath: homepage,
title: title,
//base: `${homepage}/`,
}),
new CopyPlugin({
@ -159,6 +170,21 @@ var config = {
module.exports = (env, argv) => {
if (argv.mode === "production") {
config.mode = "production";
config.optimization = {
splitChunks: { chunks: "all" },
minimize: true,
minimizer: [new TerserPlugin()],
};
// config.plugins.push(
// new CompressionPlugin({
// filename: "[path][base].gz[query]",
// algorithm: "gzip",
// test: /\.js(\?.*)?$/i,
// threshold: 10240,
// minRatio: 0.8,
// deleteOriginalAssets: true,
// })
// );
} else {
config.devtool = "cheap-module-source-map";
}

View File

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": "true",
"homepage": "/products/people",
"title": "ONLYOFFICE",
"scripts": {
"start": "webpack-cli serve",
"build": "webpack --mode production",
@ -19,6 +20,7 @@
"@svgr/webpack": "^5.5.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^7.1.2",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^3.6.0",
"html-webpack-plugin": "4.5.0",

View File

@ -89,7 +89,7 @@
height: 36px;
}
</style>
<title>ONLYOFFICE</title>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
@ -109,7 +109,7 @@
ry="3"
width="24"
height="24"
style="fill: url('#fill0')"
style="fill: url('#fill0');"
></rect>
<defs>
<linearGradient id="fill0">
@ -135,7 +135,7 @@
ry="3"
width="168"
height="24"
style="fill: url('#fill01')"
style="fill: url('#fill01');"
></rect>
<defs>
<linearGradient id="fill01">
@ -163,7 +163,7 @@
r="18"
width="36"
height="36"
style="fill: url('#fill02')"
style="fill: url('#fill02');"
></circle>
<defs>
<linearGradient id="fill02">
@ -193,7 +193,7 @@
width="100%"
height="100%"
clip-path="url(#clip-path1)"
style="fill: url('#fill1')"
style="fill: url('#fill1');"
></rect>
<defs>
<clipPath id="clip-path1">
@ -223,7 +223,7 @@
width="100%"
height="100%"
clip-path="url(#clip-path2)"
style="fill: url('#fill2')"
style="fill: url('#fill2');"
></rect>
<defs>
<clipPath id="clip-path2">

View File

@ -3,10 +3,14 @@ const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const TerserPlugin = require("terser-webpack-plugin");
//const CompressionPlugin = require("compression-webpack-plugin");
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies;
const homepage = pkg.homepage;
const title = pkg.title;
var config = {
mode: "development",
@ -15,7 +19,7 @@ var config = {
devServer: {
publicPath: homepage,
contentBase: [path.join(__dirname, "public")],
contentBase: [path.join(__dirname, "dist")],
contentBasePublicPath: homepage,
port: 5002,
historyApiFallback: {
@ -41,9 +45,11 @@ var config = {
},
output: {
publicPath: "auto", //homepage
chunkFilename: "[id].[contenthash].js",
publicPath: "auto",
chunkFilename: "js/[id].[contenthash].js",
assetModuleFilename: "assets/[hash][ext][query]",
path: path.resolve(process.cwd(), "dist"),
filename: "[name].[contenthash].bundle.js",
},
resolve: {
@ -55,6 +61,10 @@ var config = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
type: "asset/resource",
},
{
test: /\.m?js/,
type: "javascript/auto",
@ -140,6 +150,7 @@ var config = {
new HtmlWebpackPlugin({
template: "./public/index.html",
publicPath: homepage,
title: title,
//base: `${homepage}/`,
}),
new CopyPlugin({
@ -160,6 +171,21 @@ var config = {
module.exports = (env, argv) => {
if (argv.mode === "production") {
config.mode = "production";
config.optimization = {
splitChunks: { chunks: "all" },
minimize: true,
minimizer: [new TerserPlugin()],
};
// config.plugins.push(
// new CompressionPlugin({
// filename: "[path][base].gz[query]",
// algorithm: "gzip",
// test: /\.js(\?.*)?$/i,
// threshold: 10240,
// minRatio: 0.8,
// deleteOriginalAssets: true,
// })
// );
} else {
config.devtool = "cheap-module-source-map";
}

View File

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": "true",
"homepage": "",
"title": "ONLYOFFICE",
"scripts": {
"start": "webpack-cli serve",
"build": "webpack --mode production",
@ -18,15 +19,18 @@
"@babel/preset-react": "^7.12.10",
"@svgr/webpack": "^5.5.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^7.1.2",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^3.6.0",
"html-webpack-plugin": "4.5.0",
"json-loader": "^0.5.7",
"serve": "11.3.2",
"source-map-loader": "^1.1.2",
"style-loader": "1.2.1",
"webpack": "5.14.0",
"webpack-cli": "4.5.0",
"webpack-dev-server": "3.11.2",
"serve": "11.3.2"
"webpack-dev-server": "3.11.2"
},
"dependencies": {
"@babel/runtime": "^7.12.5",

View File

@ -91,12 +91,12 @@
height: 36px;
}
</style>
<title>ONLYOFFICE</title>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div class="ipl-progress-indicator" id="ipl-progress-indicator"></div>
<div id="temp-content" style="display: none">
<div id="temp-content" style="display: none;">
<header class="temp-header-container">
<div id="burger-loader-svg" class="burger-loader-svg">
<svg
@ -111,7 +111,7 @@
ry="3"
width="24"
height="24"
style="fill: url('#fill0')"
style="fill: url('#fill0');"
></rect>
<defs>
<linearGradient id="fill0">
@ -137,7 +137,7 @@
ry="3"
width="168"
height="24"
style="fill: url('#fill01')"
style="fill: url('#fill01');"
></rect>
<defs>
<linearGradient id="fill01">
@ -165,7 +165,7 @@
r="18"
width="36"
height="36"
style="fill: url('#fill02')"
style="fill: url('#fill02');"
></circle>
<defs>
<linearGradient id="fill02">
@ -194,7 +194,7 @@
width="100%"
height="100%"
clip-path="url(#clip-path1)"
style="fill: url('#fill1')"
style="fill: url('#fill1');"
></rect>
<defs>
<clipPath id="clip-path1">

View File

@ -1,17 +1,23 @@
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 TerserPlugin = require("terser-webpack-plugin");
//const CompressionPlugin = require("compression-webpack-plugin");
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies;
const homepage = pkg.homepage;
const title = pkg.title;
const config = {
entry: "./src/index",
mode: "development",
devServer: {
contentBase: path.join(__dirname, "public"),
contentBase: [path.join(__dirname, "dist")],
port: 5001,
historyApiFallback: {
// Paths with dots should still use the history fallback.
@ -44,12 +50,18 @@ const config = {
output: {
publicPath: "auto",
chunkFilename: "[id].[contenthash].js",
chunkFilename: "js/[id].[contenthash].js",
assetModuleFilename: "assets/[hash][ext][query]",
path: path.resolve(process.cwd(), "dist"),
filename: "[name].[contenthash].bundle.js",
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
type: "asset/resource",
},
{
test: /\.m?js/,
type: "javascript/auto",
@ -108,12 +120,13 @@ const config = {
},
plugins: [
new CleanWebpackPlugin(),
new ModuleFederationPlugin({
name: "studio",
filename: "remoteEntry.js",
remotes: {
studio: `studio@${homepage}/remoteEntry.js`,
people: `people@${homepage}/products/people//remoteEntry.js`,
people: `people@${homepage}/products/people/remoteEntry.js`,
files: `files@${homepage}/products/files/remoteEntry.js`,
login: `login@${homepage}/login/remoteEntry.js`,
},
@ -147,6 +160,19 @@ const config = {
new HtmlWebpackPlugin({
template: "./public/index.html",
publicPath: homepage,
title: title,
}),
new CopyPlugin({
patterns: [
{
from: "public",
globOptions: {
dot: true,
gitignore: true,
ignore: ["**/index.html"],
},
},
],
}),
],
};
@ -154,6 +180,21 @@ const config = {
module.exports = (env, argv) => {
if (argv.mode === "production") {
config.mode = "production";
config.optimization = {
splitChunks: { chunks: "all" },
minimize: true,
minimizer: [new TerserPlugin()],
};
// config.plugins.push(
// new CompressionPlugin({
// filename: "[path][base].gz[query]",
// algorithm: "gzip",
// test: /\.js(\?.*)?$/i,
// threshold: 10240,
// minRatio: 0.8,
// deleteOriginalAssets: true,
// })
// );
} else {
config.devtool = "cheap-module-source-map";
}

View File

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": "true",
"homepage": "/products/files/doceditor",
"title": "ONLYOFFICE",
"scripts": {
"start": "webpack-cli serve",
"build": "webpack --mode production",
@ -19,6 +20,7 @@
"@svgr/webpack": "^5.5.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^7.1.2",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^3.6.0",
"html-webpack-plugin": "4.5.0",

View File

@ -34,7 +34,7 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>ONLYOFFICE</title>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>

View File

@ -3,19 +3,24 @@ const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const TerserPlugin = require("terser-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies;
const homepage = pkg.homepage;
const title = pkg.title;
var config = {
mode: "development",
const config = {
entry: "./src/index",
target: "web",
mode: "development",
devServer: {
publicPath: homepage,
contentBase: [path.join(__dirname, "public")],
contentBase: [path.join(__dirname, "dist")],
contentBasePublicPath: homepage,
port: 5013,
historyApiFallback: {
@ -40,12 +45,6 @@ var config = {
},
},
output: {
publicPath: "auto", //homepage
chunkFilename: "[id].[contenthash].js",
path: path.resolve(process.cwd(), "dist"),
},
resolve: {
extensions: [".jsx", ".js", ".json"],
fallback: {
@ -53,8 +52,20 @@ var config = {
},
},
output: {
publicPath: "auto",
chunkFilename: "js/[id].[contenthash].js",
assetModuleFilename: "assets/[hash][ext][query]",
path: path.resolve(process.cwd(), "dist"),
filename: "[name].[contenthash].bundle.js",
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
type: "asset/resource",
},
{
test: /\.m?js/,
type: "javascript/auto",
@ -69,13 +80,17 @@ var config = {
loader: "@svgr/webpack",
options: {
svgoConfig: {
plugins: [{ removeViewbox: false }],
plugins: [{ removeViewBox: false }],
},
},
},
],
},
{ test: /\.json$/, loader: "json-loader" },
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/i,
use: [
@ -132,26 +147,42 @@ var config = {
new HtmlWebpackPlugin({
template: "./public/index.html",
publicPath: homepage,
title: title,
//base: `${homepage}/`,
}),
// new CopyPlugin({
// patterns: [
// {
// from: "public",
// globOptions: {
// dot: true,
// gitignore: true,
// ignore: ["**/index.html"],
// },
// },
// ],
// }),
new CopyPlugin({
patterns: [
{
from: "public",
globOptions: {
dot: true,
gitignore: true,
ignore: ["**/index.html"],
},
},
],
}),
],
};
module.exports = (env, argv) => {
if (argv.mode === "production") {
config.mode = "production";
config.optimization = {
splitChunks: { chunks: "all" },
minimize: true,
minimizer: [new TerserPlugin()],
};
config.plugins.push(
new CompressionPlugin({
filename: "[path][base].gz[query]",
algorithm: "gzip",
test: /\.js(\?.*)?$/i,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: true,
})
);
} else {
config.devtool = "cheap-module-source-map";
}

View File

@ -3,6 +3,7 @@
"version": "0.1.0",
"private": "true",
"homepage": "/login",
"title": "ONLYOFFICE",
"scripts": {
"start": "webpack-cli serve",
"build": "webpack --mode production",
@ -19,6 +20,7 @@
"@svgr/webpack": "^5.5.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"compression-webpack-plugin": "^7.1.2",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^3.6.0",
"html-webpack-plugin": "4.5.0",

View File

@ -1,14 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Login</title>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
/>
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link id="favicon" rel="shortcut icon" href="favicon.ico" />
<link rel="manifest" href="manifest.json" />
<!-- Tell the browser it's a PWA -->
<meta name="mobile-web-app-capable" content="yes" />
<!-- Tell iOS it's a PWA -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="apple-touch-icon" href="appIcon.png" />
<link
href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i"
rel="stylesheet"
type="text/css"
/>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<script>
console.log("It's LOGIN INIT");
console.log("It's Login INIT");
</script>
</body>
</html>

View File

@ -3,10 +3,14 @@ const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const TerserPlugin = require("terser-webpack-plugin");
//const CompressionPlugin = require("compression-webpack-plugin");
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies;
const homepage = pkg.homepage;
const title = pkg.title;
var config = {
mode: "development",
@ -15,7 +19,7 @@ var config = {
devServer: {
publicPath: homepage,
contentBase: [path.join(__dirname, "public")],
contentBase: [path.join(__dirname, "dist")],
contentBasePublicPath: homepage,
port: 5011,
historyApiFallback: {
@ -41,9 +45,11 @@ var config = {
},
output: {
publicPath: "auto", //homepage
chunkFilename: "[id].[contenthash].js",
publicPath: "auto",
chunkFilename: "js/[id].[contenthash].js",
assetModuleFilename: "assets/[hash][ext][query]",
path: path.resolve(process.cwd(), "dist"),
filename: "[name].[contenthash].bundle.js",
},
resolve: {
@ -55,6 +61,10 @@ var config = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
type: "asset/resource",
},
{
test: /\.m?js/,
type: "javascript/auto",
@ -69,7 +79,7 @@ var config = {
loader: "@svgr/webpack",
options: {
svgoConfig: {
plugins: [{ removeViewbox: false }],
plugins: [{ removeViewBox: false }],
},
},
},
@ -134,6 +144,7 @@ var config = {
new HtmlWebpackPlugin({
template: "./public/index.html",
publicPath: homepage,
title: title,
//base: `${homepage}/`,
}),
new CopyPlugin({
@ -154,6 +165,21 @@ var config = {
module.exports = (env, argv) => {
if (argv.mode === "production") {
config.mode = "production";
config.optimization = {
splitChunks: { chunks: "all" },
minimize: true,
minimizer: [new TerserPlugin()],
};
// config.plugins.push(
// new CompressionPlugin({
// filename: "[path][base].gz[query]",
// algorithm: "gzip",
// test: /\.js(\?.*)?$/i,
// threshold: 10240,
// minRatio: 0.8,
// deleteOriginalAssets: true,
// })
// );
} else {
config.devtool = "cheap-module-source-map";
}

864
yarn.lock

File diff suppressed because it is too large Load Diff