Web:PortalSettings:PortalPlugins: add simple plugins list and upload button
This commit is contained in:
parent
177e415b83
commit
6445e83f24
@ -0,0 +1,86 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { withTranslation } from "react-i18next";
|
||||
|
||||
import UploadButton from "./sub-components/upload-button";
|
||||
import PluginList from "./sub-components/plugin-list";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: flex;
|
||||
|
||||
flex-direction: column;
|
||||
|
||||
.plugins__upload-button {
|
||||
width: 110px;
|
||||
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.custom-plugin-input {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const PortalPlugins = ({ t, setDocumentTitle, theme }) => {
|
||||
const [plugins, setPlugins] = React.useState(null);
|
||||
|
||||
setDocumentTitle(`Portal plugins`);
|
||||
|
||||
const onActivate = React.useCallback(
|
||||
(id, status) => {
|
||||
setPlugins((val) => {
|
||||
const newPlugins = val;
|
||||
|
||||
const idx = newPlugins.findIndex((plugin) => +plugin.id === +id);
|
||||
|
||||
if (idx > -1) {
|
||||
newPlugins[idx].isActive = status === "true";
|
||||
}
|
||||
|
||||
return [...newPlugins];
|
||||
});
|
||||
},
|
||||
[plugins]
|
||||
);
|
||||
|
||||
const addPlugin = React.useCallback((plugin) => {
|
||||
setPlugins((value) => {
|
||||
if (value) return [...value, plugin];
|
||||
|
||||
return [plugin];
|
||||
});
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const newPlugins = [];
|
||||
|
||||
Array.from(window.PluginStore.plugins, ([key, value]) =>
|
||||
newPlugins.push(value)
|
||||
);
|
||||
|
||||
setPlugins(newPlugins);
|
||||
}, [window.PluginStore]);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<UploadButton t={t} addPlugin={addPlugin} />
|
||||
{plugins && (
|
||||
<PluginList plugins={plugins} onActivate={onActivate} theme={theme} />
|
||||
)}
|
||||
</StyledContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default inject(({ auth }) => {
|
||||
const { settingsStore, setDocumentTitle } = auth;
|
||||
const { theme } = settingsStore;
|
||||
|
||||
return {
|
||||
theme,
|
||||
setDocumentTitle,
|
||||
};
|
||||
})(withTranslation(["Settings", "Common"])(observer(PortalPlugins)));
|
@ -0,0 +1,160 @@
|
||||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
import { isMobile } from "react-device-detect";
|
||||
|
||||
import RowContainer from "@docspace/components/row-container";
|
||||
import RowContent from "@docspace/components/row-content";
|
||||
import Row from "@docspace/components/row";
|
||||
|
||||
import Text from "@docspace/components/text";
|
||||
|
||||
import { tablet } from "@docspace/components/utils/device";
|
||||
import { Base } from "@docspace/components/themes";
|
||||
|
||||
import { activatePlugin } from "SRC_DIR/helpers/plugins";
|
||||
|
||||
const StyledHeader = styled.div`
|
||||
display: ${isMobile ? "none" : "flex"};
|
||||
border-bottom: ${(props) => props.theme.connectedClouds.borderBottom};
|
||||
padding-bottom: 12px;
|
||||
|
||||
@media ${tablet} {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.plugins__plugin {
|
||||
width: 30%;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.plugins__text-container {
|
||||
display: flex;
|
||||
margin-left: 6px;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.plugins__separator {
|
||||
display: block;
|
||||
height: 10px;
|
||||
margin: 4px 8px 0 0;
|
||||
z-index: 1;
|
||||
border-right: ${(props) => props.theme.connectedClouds.borderRight};
|
||||
}
|
||||
`;
|
||||
|
||||
StyledHeader.defaultProps = { theme: Base };
|
||||
|
||||
const StyledRow = styled(Row)`
|
||||
.row-main-container-wrapper {
|
||||
margin-right: 40px;
|
||||
}
|
||||
`;
|
||||
|
||||
const PluginList = ({ plugins, onActivate, theme }) => {
|
||||
const onActivateAction = React.useCallback(
|
||||
(e) => {
|
||||
const { dataset } = (e.originalEvent || e).currentTarget;
|
||||
|
||||
activatePlugin(dataset.id, dataset.status);
|
||||
onActivate(dataset.id, dataset.status);
|
||||
},
|
||||
[onActivate]
|
||||
);
|
||||
|
||||
const getContextOptions = React.useCallback(
|
||||
(plugin, index) => {
|
||||
const activateItem = plugin.isActive
|
||||
? {
|
||||
key: `${index}_disable`,
|
||||
"data-id": plugin.id,
|
||||
"data-status": !plugin.isActive,
|
||||
label: "Disable",
|
||||
onClick: onActivateAction,
|
||||
}
|
||||
: {
|
||||
key: `${index}_activate`,
|
||||
"data-id": plugin.id,
|
||||
"data-status": !plugin.isActive,
|
||||
label: "Activate",
|
||||
onClick: onActivateAction,
|
||||
};
|
||||
|
||||
return [activateItem];
|
||||
},
|
||||
[onActivateAction]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledHeader>
|
||||
<Text
|
||||
className="plugins__plugin"
|
||||
fontSize="12px"
|
||||
fontWeight={600}
|
||||
color={theme.connectedClouds.color}
|
||||
noSelect
|
||||
>
|
||||
Plugin
|
||||
</Text>
|
||||
<div></div>
|
||||
|
||||
<div className="plugins__text-container">
|
||||
<div className="plugins__separator" />
|
||||
<Text
|
||||
className="plugins__status"
|
||||
fontSize="12px"
|
||||
fontWeight={600}
|
||||
color={theme.connectedClouds.color}
|
||||
noSelect
|
||||
>
|
||||
Status
|
||||
</Text>
|
||||
</div>
|
||||
</StyledHeader>
|
||||
<RowContainer useReactWindow={false}>
|
||||
{plugins
|
||||
? plugins.map((plugin, index) => {
|
||||
const name = plugin.getPluginName();
|
||||
const version = plugin.getPluginVersion();
|
||||
|
||||
return (
|
||||
<StyledRow
|
||||
key={plugin.id}
|
||||
contextOptions={getContextOptions(plugin, index)}
|
||||
>
|
||||
<RowContent>
|
||||
<Text
|
||||
as="div"
|
||||
type="page"
|
||||
fontSize="13px"
|
||||
fontWeight={600}
|
||||
title={plugin.name}
|
||||
noSelect
|
||||
containerWidth="30%"
|
||||
>
|
||||
{name} {version}
|
||||
</Text>
|
||||
<div></div>
|
||||
|
||||
<Text
|
||||
as="div"
|
||||
type="page"
|
||||
fontSize="13px"
|
||||
fontWeight={600}
|
||||
title={plugin.isActive ? "Active" : "Disabled"}
|
||||
noSelect
|
||||
containerWidth="70%"
|
||||
>
|
||||
{plugin.isActive ? "Active" : "Disabled"}
|
||||
</Text>
|
||||
</RowContent>
|
||||
</StyledRow>
|
||||
);
|
||||
})
|
||||
: "Loading"}
|
||||
</RowContainer>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(PluginList);
|
@ -0,0 +1,65 @@
|
||||
import React from "react";
|
||||
|
||||
import Button from "@docspace/components/button";
|
||||
|
||||
import api from "SRC_DIR/helpers/plugins/api";
|
||||
import { initPlugin } from "SRC_DIR/helpers/plugins";
|
||||
|
||||
const UploadButton = ({ t, addPlugin }) => {
|
||||
const inputPluginElement = React.useRef(null);
|
||||
|
||||
const uploadPlugin = React.useCallback(
|
||||
async (files) => {
|
||||
if (!files) return;
|
||||
|
||||
let formData = new FormData();
|
||||
|
||||
for (let index in Object.keys(files)) {
|
||||
formData.append(files[index].name, files[index]);
|
||||
}
|
||||
|
||||
try {
|
||||
const plugin = await api.uploadPlugin(formData);
|
||||
|
||||
initPlugin(plugin, addPlugin);
|
||||
// addPlugin(plugin);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
[addPlugin]
|
||||
);
|
||||
|
||||
const onInput = React.useCallback(
|
||||
(e) => {
|
||||
uploadPlugin(e.target.files);
|
||||
e.target.value = null;
|
||||
},
|
||||
[uploadPlugin]
|
||||
);
|
||||
|
||||
const onUploadPluginClick = React.useCallback(() => {
|
||||
inputPluginElement.current.click();
|
||||
}, [inputPluginElement.current]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
className={"plugins__upload-button"}
|
||||
size={"small"}
|
||||
label={"Upload plugin"}
|
||||
primary
|
||||
onClick={onUploadPluginClick}
|
||||
/>
|
||||
<input
|
||||
ref={inputPluginElement}
|
||||
id="customPluginInput"
|
||||
className="custom-plugin-input"
|
||||
type="file"
|
||||
onInput={onInput}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(UploadButton);
|
Loading…
Reference in New Issue
Block a user