Web: Client: PortalSettings: Fixed OAuth settings page

This commit is contained in:
Ilya Oleshko 2023-06-27 10:10:13 +03:00
parent a0b9e56097
commit fbaace1941
9 changed files with 171 additions and 340 deletions

View File

@ -1,109 +0,0 @@
import React, { useState } from "react";
import { inject, observer } from "mobx-react";
import { Row as ComponentRow } from "@docspace/components/row";
import { RowContent } from "./RowContent";
import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url";
import HistoryIcon from "PUBLIC_DIR/images/history.react.svg?url";
import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url";
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
export const Row = (props) => {
const {
webhook,
sectionWidth,
toggleEnabled,
openSettingsModal,
openDeleteModal,
setCurrentWebhook,
} = props;
const navigate = useNavigate();
const { t } = useTranslation(["Webhooks", "Common"]);
const [isChecked, setIsChecked] = useState(webhook.enabled);
const handleToggleEnabled = () => {
toggleEnabled(webhook);
setIsChecked((prevIsChecked) => !prevIsChecked);
};
const redirectToHistory = () => {
navigate(window.location.pathname + `/${webhook.id}`);
};
const handleRowClick = (e) => {
if (
e.target.closest(".table-container_row-context-menu-wrapper") ||
e.target.closest(".toggleButton") ||
e.target.closest(".row_context-menu-wrapper") ||
e.detail === 0
) {
return;
}
redirectToHistory();
};
const onSettingsOpen = () => {
setCurrentWebhook(webhook);
openSettingsModal();
};
const onDeleteOpen = () => {
setCurrentWebhook(webhook);
openDeleteModal();
};
const contextOptions = [
{
key: "Settings dropdownItem",
label: t("Common:Settings"),
icon: SettingsIcon,
onClick: onSettingsOpen,
},
{
key: "Webhook history dropdownItem",
label: t("WebhookHistory"),
icon: HistoryIcon,
onClick: redirectToHistory,
},
{
key: "Separator dropdownItem",
isSeparator: true,
},
{
key: "Delete webhook dropdownItem",
label: t("DeleteWebhook"),
icon: DeleteIcon,
onClick: onDeleteOpen,
},
];
return (
<>
<ComponentRow
sectionWidth={sectionWidth}
key={webhook.id}
data={webhook}
contextOptions={contextOptions}
onClick={handleRowClick}
>
<RowContent
sectionWidth={sectionWidth}
webhook={webhook}
isChecked={isChecked}
handleToggleEnabled={handleToggleEnabled}
/>
</ComponentRow>
</>
);
};
export default inject(({ webhooksStore }) => {
const { toggleEnabled, deleteWebhook, editWebhook, setCurrentWebhook } =
webhooksStore;
return { toggleEnabled, deleteWebhook, editWebhook, setCurrentWebhook };
})(observer(Row));

View File

@ -1,78 +0,0 @@
import React from "react";
import styled from "styled-components";
import Text from "@docspace/components/text";
import { RowContent as ComponentRowContent } from "@docspace/components/row-content";
import ToggleButton from "@docspace/components/toggle-button";
//import StatusBadge from "../../StatusBadge";
import { isMobileOnly } from "react-device-detect";
const StyledRowContent = styled(ComponentRowContent)`
display: flex;
padding-bottom: 10px;
.rowMainContainer {
height: 100%;
width: 100%;
}
.mainIcons {
min-width: 76px;
}
`;
const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
justify-items: center;
`;
const ToggleButtonWrapper = styled.div`
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
margin-left: -52px;
`;
const FlexWrapper = styled.div`
display: flex;
`;
export const RowContent = ({
sectionWidth,
webhook,
isChecked,
handleToggleEnabled,
}) => {
return (
<StyledRowContent sectionWidth={sectionWidth}>
<ContentWrapper>
<FlexWrapper>
<Text fontWeight={600} fontSize="14px" style={{ marginRight: "8px" }}>
{webhook.name}
</Text>
{/* <StatusBadge status={webhook.status} /> */}
</FlexWrapper>
{!isMobileOnly && (
<Text fontWeight={600} fontSize="12px" color="#A3A9AE">
{webhook.uri}
</Text>
)}
</ContentWrapper>
<ToggleButtonWrapper>
<ToggleButton
className="toggle toggleButton"
id="toggle id"
isChecked={isChecked}
onChange={handleToggleEnabled}
/>
</ToggleButtonWrapper>
</StyledRowContent>
);
};

View File

@ -1,60 +0,0 @@
import React, { useEffect } from "react";
import styled from "styled-components";
import { inject, observer } from "mobx-react";
import { isMobile } from "react-device-detect";
import RowContainer from "@docspace/components/row-container";
import Row from "./Row";
const StyledRowContainer = styled(RowContainer)`
margin-top: 16px;
`;
const RowView = (props) => {
const {
webhooks,
sectionWidth,
viewAs,
setViewAs,
openSettingsModal,
openDeleteModal,
} = props;
useEffect(() => {
if (viewAs !== "table" && viewAs !== "row") return;
if (sectionWidth < 1025 || isMobile) {
viewAs !== "row" && setViewAs("row");
} else {
viewAs !== "table" && setViewAs("table");
}
}, [sectionWidth]);
return (
<StyledRowContainer useReactWindow={false}>
{webhooks.map((webhook) => (
<Row
key={webhook.id}
webhook={webhook}
sectionWidth={sectionWidth}
openSettingsModal={openSettingsModal}
openDeleteModal={openDeleteModal}
/>
))}
</StyledRowContainer>
);
};
export default inject(({ webhooksStore, setup }) => {
const { webhooks } = webhooksStore;
const { viewAs, setViewAs } = setup;
return {
webhooks,
viewAs,
setViewAs,
};
})(observer(RowView));

View File

@ -1,11 +1,11 @@
import React, { useState } from "react";
import { TableHeader as Header } from "@docspace/components/table-container/TableHeader";
import TableHeader from "@docspace/components/table-container/TableHeader";
import { useTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
const TABLE_VERSION = "5";
const TABLE_COLUMNS = `webhooksConfigColumns_ver-${TABLE_VERSION}`;
const TABLE_VERSION = "1";
const TABLE_COLUMNS = `oauthConfigColumns_ver-${TABLE_VERSION}`;
const getColumns = (defaultColumns, userId) => {
const storageColumns = localStorage.getItem(`${TABLE_COLUMNS}=${userId}`);
@ -26,7 +26,7 @@ const getColumns = (defaultColumns, userId) => {
}
};
const TableHeader = (props) => {
const Header = (props) => {
const {
userId,
sectionWidth,
@ -38,6 +38,15 @@ const TableHeader = (props) => {
const { t } = useTranslation(["Webhooks", "Common"]);
const defaultColumns = [
{
key: "Logo",
title: "Logo",
enable: true,
active: true,
resizable: false,
defaultSize: 64,
onChange: onColumnChange,
},
{
key: "Name",
title: t("Common:Name"),
@ -49,17 +58,19 @@ const TableHeader = (props) => {
onChange: onColumnChange,
},
{
key: "URL",
title: t("URL"),
enable: true,
key: "Description",
title: "Description",
resizable: true,
enable: true,
minWidth: 150,
onChange: onColumnChange,
},
{
key: "State",
title: t("State"),
key: "Enable",
title: "Enable",
enable: true,
resizable: true,
resizable: false,
defaultSize: 64,
onChange: onColumnChange,
},
];
@ -82,7 +93,7 @@ const TableHeader = (props) => {
}
return (
<Header
<TableHeader
checkboxSize="48px"
containerRef={tableRef}
columns={columns}
@ -102,4 +113,4 @@ export default inject(({ auth }) => {
return {
userId: auth.userStore.user.id,
};
})(observer(TableHeader));
})(observer(Header));

View File

@ -1,6 +1,6 @@
import React, { useState } from "react";
import styled from "styled-components";
import { TableRow as Row } from "@docspace/components/table-container/TableRow";
import TableRow from "@docspace/components/table-container/TableRow";
import TableCell from "@docspace/components/table-container/TableCell";
import Text from "@docspace/components/text";
@ -8,6 +8,7 @@ import ToggleButton from "@docspace/components/toggle-button";
import SettingsIcon from "PUBLIC_DIR/images/catalog.settings.react.svg?url";
import HistoryIcon from "PUBLIC_DIR/images/history.react.svg?url";
import DeleteIcon from "PUBLIC_DIR/images/delete.react.svg?url";
import LinuxIcon from "PUBLIC_DIR/images/linux.react.svg?url";
//import StatusBadge from "../../StatusBadge";
import { useNavigate } from "react-router-dom";
@ -19,7 +20,7 @@ const StyledWrapper = styled.div`
display: contents;
`;
const StyledTableRow = styled(Row)`
const StyledTableRow = styled(TableRow)`
.table-container_cell {
padding-right: 30px;
text-overflow: ellipsis;
@ -28,30 +29,35 @@ const StyledTableRow = styled(Row)`
.mr-8 {
margin-right: 8px;
}
.textOverflow {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.toggleButton {
display: contents;
}
`;
const TableRow = (props) => {
const Row = (props) => {
const {
webhook,
toggleEnabled,
item,
setEnabled,
openSettingsModal,
openDeleteModal,
setCurrentWebhook,
setCurrentProject,
hideColumns,
} = props;
const navigate = useNavigate();
const { t } = useTranslation(["Webhooks", "Common"]);
const [isChecked, setIsChecked] = useState(webhook.enabled);
const [isChecked, setIsChecked] = useState(item.token.enable);
const redirectToHistory = () => {
navigate(window.location.pathname + `/${webhook.id}`);
navigate(window.location.pathname + `/${item.id}`);
};
const handleRowClick = (e) => {
@ -69,39 +75,33 @@ const TableRow = (props) => {
redirectToHistory();
};
const handleToggleEnabled = () => {
toggleEnabled(webhook);
setEnabled(item.id);
setIsChecked((prevIsChecked) => !prevIsChecked);
};
const onSettingsOpen = () => {
setCurrentWebhook(webhook);
openSettingsModal();
setCurrentProject(item);
//openSettingsModal();
};
const onDeleteOpen = () => {
setCurrentWebhook(webhook);
openDeleteModal();
setCurrentProject(item);
//openDeleteModal();
};
const contextOptions = [
{
key: "Settings dropdownItem",
key: "settings",
label: t("Common:Settings"),
icon: SettingsIcon,
onClick: onSettingsOpen,
},
{
key: "Webhook history dropdownItem",
label: t("WebhookHistory"),
icon: HistoryIcon,
onClick: redirectToHistory,
},
{
key: "Separator dropdownItem",
isSeparator: true,
},
{
key: "Delete webhook dropdownItem",
label: t("DeleteWebhook"),
key: "delete",
label: t("Common:Delete"),
icon: DeleteIcon,
onClick: onDeleteOpen,
},
@ -115,26 +115,21 @@ const TableRow = (props) => {
hideColumns={hideColumns}
>
<TableCell>
<Text as="span" fontWeight={600} className="mr-8 textOverflow">
{webhook.name}{" "}
</Text>
{/* <StatusBadge status={webhook.status} /> */}
<img src={LinuxIcon} />
</TableCell>
<TableCell>
<Text
as="span"
fontSize="11px"
color="#A3A9AE"
fontWeight={600}
className="textOverflow"
>
{webhook.uri}
<Text as="span" fontWeight={600} className="mr-8 textOverflow">
{item.general.name}
</Text>
</TableCell>
<TableCell>
<Text as="span" fontWeight={400} className="mr-8 textOverflow">
{item.general.description}
</Text>
</TableCell>
<TableCell>
<ToggleButton
className="toggle toggleButton"
id="toggle id"
isChecked={isChecked}
onChange={handleToggleEnabled}
/>
@ -145,11 +140,8 @@ const TableRow = (props) => {
);
};
export default inject(({ webhooksStore }) => {
const { toggleEnabled, setCurrentWebhook } = webhooksStore;
export default inject(({ oauthStore }) => {
const { setCurrentProject, setEnabled } = oauthStore;
return {
toggleEnabled,
setCurrentWebhook,
};
})(observer(TableRow));
return { setEnabled, setCurrentProject };
})(observer(Row));

View File

@ -7,8 +7,8 @@ import styled from "styled-components";
import TableContainer from "@docspace/components/table-container/TableContainer";
import TableBody from "@docspace/components/table-container/TableBody";
import TableRow from "./TableRow";
import TableHeader from "./TableHeader";
import Row from "./Row";
import Header from "./Header";
import { Base } from "@docspace/components/themes";
@ -35,14 +35,14 @@ const TableWrapper = styled(TableContainer)`
TableWrapper.defaultProps = { theme: Base };
const TABLE_VERSION = "5";
const COLUMNS_SIZE = `webhooksConfigColumnsSize_ver-${TABLE_VERSION}`;
const INFO_PANEL_COLUMNS_SIZE = `infoPanelWebhooksConfigColumnsSize_ver-${TABLE_VERSION}`;
const TABLE_VERSION = "1";
const COLUMNS_SIZE = `oauthConfigColumnsSize_ver-${TABLE_VERSION}`;
const INFO_PANEL_COLUMNS_SIZE = `infoPanelOauthConfigColumnsSize_ver-${TABLE_VERSION}`;
const TableView = (props) => {
const {
webhooks,
loadWebhooks,
items,
getProjects,
sectionWidth,
viewAs,
setViewAs,
@ -68,7 +68,7 @@ const TableView = (props) => {
return (
<TableWrapper forwardedRef={tableRef} useReactWindow>
<TableHeader
<Header
sectionWidth={sectionWidth}
tableRef={tableRef}
columnStorageName={columnStorageName}
@ -81,15 +81,15 @@ const TableView = (props) => {
infoPanelVisible={false}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
filesLength={webhooks.length}
fetchMoreFiles={loadWebhooks}
filesLength={items.length}
fetchMoreFiles={getProjects}
hasMoreFiles={false}
itemCount={webhooks.length}
itemCount={items.length}
>
{webhooks.map((webhook, index) => (
<TableRow
key={webhook.id}
webhook={webhook}
{items.map((item, index) => (
<Row
key={item.id}
item={item}
index={index}
openSettingsModal={openSettingsModal}
openDeleteModal={openDeleteModal}
@ -101,17 +101,16 @@ const TableView = (props) => {
);
};
export default inject(({ webhooksStore, setup, auth }) => {
const { webhooks, loadWebhooks } = webhooksStore;
export default inject(({ oauthStore, setup, auth }) => {
const { getProjects } = oauthStore;
const { viewAs, setViewAs } = setup;
const { id: userId } = auth.userStore.user;
return {
webhooks,
viewAs,
setViewAs,
loadWebhooks,
getProjects,
userId,
};
})(observer(TableView));

View File

@ -4,35 +4,27 @@ import { inject, observer } from "mobx-react";
import { Consumer } from "@docspace/components/utils/context";
import TableView from "./TableView";
import RowView from "./RowView";
const List = (props) => {
const { viewAs, openSettingsModal, openDeleteModal } = props;
const List = ({ viewAs, openSettingsModal, openDeleteModal, projects }) => {
return (
<Consumer>
{(context) =>
viewAs === "table" ? (
{(context) => (
<TableView
items={projects}
sectionWidth={context.sectionWidth}
openSettingsModal={openSettingsModal}
openDeleteModal={openDeleteModal}
/>
) : (
<RowView
sectionWidth={context.sectionWidth}
openSettingsModal={openSettingsModal}
openDeleteModal={openDeleteModal}
/>
)
}
)}
</Consumer>
);
};
export default inject(({ setup }) => {
export default inject(({ setup, oauthStore }) => {
const { viewAs } = setup;
const { projects } = oauthStore;
return {
viewAs,
projects,
};
})(observer(List));

View File

@ -0,0 +1,80 @@
import { makeAutoObservable, runInAction } from "mobx";
const projects = [...Array(10)].map((value, index) => {
return {
id: index,
general: {
name: `Project ${index}`,
description: `Description ${index}`,
},
credentials: {
client_id: "random_client_id",
client_secret: "random_client_secret",
},
token: {
enable: true,
bearer_only: true,
public_client: false,
},
scopes: {
files: {
read: true,
write: true,
},
workspaces: {
read: false,
write: false,
},
users: {
read: false,
write: false,
},
},
links: {
installation_url: "https://example.com/install",
redirect_url: "https://example.com/redirect",
allowed_origins: "https://example.com",
},
};
});
class OAuthStore {
projects = projects;
currentProject = {};
constructor() {
makeAutoObservable(this);
}
getProjects = () => {
this.projects = projects;
};
setCurrentProject = (project) => {
this.currentProject = project;
};
addProject = (project) => {
this.projects = [...this.projects, project];
};
setEnabled = (id) => {
const index = this.projects.findIndex((proj) => proj.id === id);
this.projects[index].token.enable = !this.projects[index].token.enable;
};
deleteProject = (id) => {
this.projects = this.projects.filter((proj) => proj.id !== id);
};
editProject = (project) => {
const index = this.projects.findIndex((proj) => proj.id === project.id);
runInAction(() => {
this.projects[index] = project;
});
};
}
export default OAuthStore;

View File

@ -37,6 +37,7 @@ import CreateEditRoomStore from "./CreateEditRoomStore";
import WebhooksStore from "./WebhooksStore";
import ClientLoadingStore from "./ClientLoadingStore";
import OAuthStore from "./OAuthStore";
const oformsStore = new OformsStore(authStore);
@ -172,6 +173,8 @@ const createEditRoomStore = new CreateEditRoomStore(
const webhooksStore = new WebhooksStore();
const oauthStore = new OAuthStore();
const store = {
auth: authStore,
payments: paymentStore,
@ -210,6 +213,7 @@ const store = {
webhooksStore,
clientLoadingStore,
oauthStore,
};
export default store;