Web:Client:OAuth: add row view

This commit is contained in:
Timofey Boyko 2023-09-28 10:21:43 +03:00
parent 807215a0cb
commit ca73c5b0c4
8 changed files with 392 additions and 11 deletions

View File

@ -0,0 +1,85 @@
import { useNavigate } from "react-router-dom";
import { useTranslation } from "react-i18next";
//@ts-ignore
import Row from "@docspace/components/row";
import ToggleButton from "@docspace/components/toggle-button";
import { RowContent } from "./RowContent";
import { RowProps } from "./RowView.types";
export const OAuthRow = (props: RowProps) => {
const {
item,
sectionWidth,
changeClientStatus,
isChecked,
inProgress,
getContextMenuItems,
setSelection,
} = props;
const navigate = useNavigate();
const { t } = useTranslation(["Common"]);
const editClient = () => {
navigate(`${item.clientId}`);
};
const handleToggleEnabled = async () => {
if (!changeClientStatus) return;
await changeClientStatus(item.clientId, !item.enabled);
};
const handleRowClick = (e: any) => {
if (
e.target.closest(".checkbox") ||
e.target.closest(".table-container_row-checkbox") ||
e.detail === 0
) {
return;
}
if (
e.target.closest(".table-container_row-context-menu-wrapper") ||
e.target.closest(".toggleButton") ||
e.target.closest(".row_context-menu-wrapper")
) {
return setSelection && setSelection("");
}
editClient();
};
const contextOptions = getContextMenuItems && getContextMenuItems(t, item);
const element = <img src={item.logoUrl} alt={"App logo"} />;
return (
<>
<Row
sectionWidth={sectionWidth}
key={item.clientId}
data={item}
contextOptions={contextOptions}
onClick={handleRowClick}
element={element}
mode={"modern"}
checked={isChecked}
inProgress={inProgress}
onSelect={() => setSelection && setSelection(item.clientId)}
>
<RowContent
sectionWidth={sectionWidth}
item={item}
isChecked={isChecked}
inProgress={inProgress}
setSelection={setSelection}
handleToggleEnabled={handleToggleEnabled}
/>
</Row>
</>
);
};
export default OAuthRow;

View File

@ -0,0 +1,57 @@
import React from "react";
import Text from "@docspace/components/text";
import ToggleButton from "@docspace/components/toggle-button";
import { isMobileOnly } from "react-device-detect";
import {
StyledRowContent,
ContentWrapper,
FlexWrapper,
ToggleButtonWrapper,
} from "./RowView.styled";
import { RowContentProps } from "./RowView.types";
export const RowContent = ({
sectionWidth,
item,
handleToggleEnabled,
}: RowContentProps) => {
return (
<StyledRowContent sectionWidth={sectionWidth}>
<ContentWrapper>
<FlexWrapper>
{/* @ts-ignore */}
<Text
fontWeight={600}
fontSize="14px"
style={{ marginInlineEnd: "8px" }}
>
{item.name}
</Text>
</FlexWrapper>
{!isMobileOnly && (
<>
{/* @ts-ignore */}
<Text fontWeight={600} fontSize="12px" color="#A3A9AE">
{item.description}
</Text>
</>
)}
</ContentWrapper>
<ToggleButtonWrapper>
<ToggleButton
className="toggle toggleButton"
id="toggle id"
isChecked={item.enabled}
onChange={handleToggleEnabled}
/>
</ToggleButtonWrapper>
</StyledRowContent>
);
};

View File

@ -0,0 +1,67 @@
import styled from "styled-components";
//@ts-ignore
import RowContainer from "@docspace/components/row-container";
//@ts-ignore
import RowContent from "@docspace/components/row-content";
export const StyledRowContainer = styled(RowContainer)`
margin-top: 0px;
.row-list-item {
padding-left: 21px;
}
.row-loader {
width: calc(100% - 46px) !important;
padding-left: 21px;
}
img {
width: 32px;
max-width: 32px;
height: 32px;
max-height: 32px;
}
`;
export const StyledRowContent = styled(RowContent)`
display: flex;
padding-bottom: 10px;
.rowMainContainer {
height: 100%;
width: 100%;
}
.mainIcons {
min-width: 76px;
}
`;
export const ContentWrapper = styled.div`
display: flex;
flex-direction: column;
justify-items: center;
`;
export const ToggleButtonWrapper = styled.div`
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
label {
margin-top: 1px;
position: relative;
gap: 0px;
margin-right: -8px;
}
`;
export const FlexWrapper = styled.div`
display: flex;
`;

View File

@ -0,0 +1,49 @@
import { ClientProps } from "@docspace/common/utils/oauth/interfaces";
//@ts-ignore
import { ViewAsType } from "SRC_DIR/store/OAuthStore";
export interface RowViewProps {
items: ClientProps[];
sectionWidth: number;
viewAs?: ViewAsType;
setViewAs?: (value: ViewAsType) => void;
selection?: string[];
setSelection?: (clientId: string) => void;
getContextMenuItems?: (
t: any,
item: ClientProps
) => {
[key: string]: any | string | boolean | ((clientId: string) => void);
}[];
activeClients?: string[];
hasNextPage?: boolean;
totalElements?: number;
fetchNextClients?: (startIndex: number) => Promise<void>;
changeClientStatus?: (clientId: string, status: boolean) => Promise<void>;
}
export interface RowProps {
item: ClientProps;
isChecked: boolean;
inProgress: boolean;
sectionWidth: number;
getContextMenuItems?: (
t: any,
item: ClientProps
) => {
[key: string]: any | string | boolean | ((clientId: string) => void);
}[];
setSelection?: (clientId: string) => void;
changeClientStatus?: (clientId: string, status: boolean) => Promise<void>;
}
export interface RowContentProps {
sectionWidth: number;
item: ClientProps;
isChecked: boolean;
inProgress: boolean;
handleToggleEnabled: () => void;
setSelection?: (clientId: string) => void;
changeClientStatus?: (clientId: string, status: boolean) => Promise<void>;
}

View File

@ -0,0 +1,99 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { isMobile } from "react-device-detect";
//@ts-ignore
import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore";
import OAuthRow from "./Row";
import { RowViewProps } from "./RowView.types";
import { StyledRowContainer } from "./RowView.styled";
const RowView = (props: RowViewProps) => {
const {
items,
sectionWidth,
viewAs,
setViewAs,
changeClientStatus,
selection,
setSelection,
activeClients,
getContextMenuItems,
hasNextPage,
totalElements,
fetchNextClients,
} = props;
React.useEffect(() => {
if (viewAs !== "table" && viewAs !== "row") return;
if (sectionWidth < 1025 || isMobile) {
viewAs !== "row" && setViewAs && setViewAs("row");
} else {
viewAs !== "table" && setViewAs && setViewAs("table");
}
}, [viewAs, setViewAs, sectionWidth]);
return (
<StyledRowContainer
itemHeight={59}
filesLength={items.length}
fetchMoreFiles={({
startIndex,
}: {
startIndex: number;
stopIndex: number;
}) => fetchNextClients && fetchNextClients(startIndex)}
hasMoreFiles={hasNextPage}
itemCount={totalElements}
useReactWindow={true}
>
{items.map((item) => (
<OAuthRow
key={item.clientId}
item={item}
isChecked={selection?.includes(item.clientId) || false}
inProgress={activeClients?.includes(item.clientId) || false}
setSelection={setSelection}
changeClientStatus={changeClientStatus}
getContextMenuItems={getContextMenuItems}
sectionWidth={sectionWidth}
/>
))}
</StyledRowContainer>
);
};
export default inject(
({ oauthStore }: { auth: any; oauthStore: OAuthStoreProps }) => {
const {
viewAs,
setViewAs,
selection,
setSelection,
changeClientStatus,
getContextMenuItems,
activeClients,
hasNextPage,
totalElements,
fetchNextClients,
} = oauthStore;
return {
viewAs,
setViewAs,
changeClientStatus,
selection,
setSelection,
activeClients,
getContextMenuItems,
hasNextPage,
totalElements,
fetchNextClients,
};
}
)(observer(RowView));

View File

@ -22,7 +22,7 @@ const Row = (props: RowProps) => {
} = props;
const navigate = useNavigate();
const { t } = useTranslation(["Webhooks", "Common"]);
const { t } = useTranslation(["Common"]);
const editClient = () => {
navigate(`${item.clientId}`);

View File

@ -11,6 +11,8 @@ import { Consumer } from "@docspace/components/utils/context";
import { ViewAsType } from "SRC_DIR/store/OAuthStore";
import TableView from "./TableView";
import RowView from "./RowView";
import RegisterNewButton from "../RegisterNewButton";
const StyledContainer = styled.div`
@ -82,7 +84,12 @@ const List = ({ t, clients, viewAs, setViewAs }: ListProps) => {
sectionWidth={context.sectionWidth}
/>
) : (
<div>row</div>
<RowView
viewAs={viewAs}
setViewAs={setViewAs}
items={clients || []}
sectionWidth={context.sectionWidth}
/>
)}
</>
)}

View File

@ -37,6 +37,9 @@ export interface OAuthStoreProps {
deleteDialogVisible: boolean;
setDeleteDialogVisible: (value: boolean) => void;
clientsIsLoading: boolean;
setClientsIsLoading: (value: boolean) => void;
editClient: (clientId: string) => void;
clients: ClientProps[];
@ -85,7 +88,7 @@ export interface OAuthStoreProps {
class OAuthStore implements OAuthStoreProps {
viewAs: "table" | "row" = "table";
currentPage: number = 0;
currentPage: number = -1;
totalPages: number = 0;
totalElements: number = 0;
@ -103,6 +106,8 @@ class OAuthStore implements OAuthStoreProps {
scopes: Scope[] = [];
clientsIsLoading: boolean = true;
constructor() {
makeAutoObservable(this);
}
@ -135,6 +140,10 @@ class OAuthStore implements OAuthStoreProps {
}
};
setClientsIsLoading = (value: boolean) => {
this.clientsIsLoading = value;
};
setActiveClient = (clientId: string) => {
if (!clientId) {
this.activeClients = [];
@ -175,10 +184,7 @@ class OAuthStore implements OAuthStoreProps {
fetchClients = async () => {
try {
runInAction(() => {
this.currentPage = 1;
});
this.setClientsIsLoading(true);
const clientList: ClientListProps = await getClientList(0, PAGE_LIMIT);
runInAction(() => {
@ -186,14 +192,23 @@ class OAuthStore implements OAuthStoreProps {
this.totalElements = clientList.totalElements;
this.clients = clientList.content;
this.selection = [];
this.currentPage = 1;
});
this.setClientsIsLoading(false);
} catch (e) {
console.log(e);
}
};
fetchNextClients = async (startIndex: number) => {
if (this.clientsIsLoading) return;
this.setClientsIsLoading(true);
const page = startIndex / PAGE_LIMIT;
console.log(page);
runInAction(() => {
this.currentPage = page + 1;
});
@ -205,6 +220,8 @@ class OAuthStore implements OAuthStoreProps {
this.totalElements = clientList.totalElements;
this.clients = [...this.clients, ...clientList.content];
});
this.setClientsIsLoading(false);
};
//TODO: OAuth, add tenant and other params
@ -338,21 +355,21 @@ class OAuthStore implements OAuthStoreProps {
const settingsOption = {
key: "settings",
icon: SettingsIcon,
label: t("Common:Settings"),
label: t("Settings"),
onClick: () => this.editClient(clientId),
};
const enableOption = {
key: "enable",
icon: EnableReactSvgUrl,
label: t("Common:Enable"),
label: t("Enable"),
onClick: () => onEnable(true),
};
const disableOption = {
key: "disable",
icon: RemoveReactSvgUrl,
label: t("Common:Disable"),
label: t("Disable"),
onClick: () => onEnable(false),
};
@ -363,7 +380,7 @@ class OAuthStore implements OAuthStoreProps {
},
{
key: "delete",
label: t("Common:Delete"),
label: t("Delete"),
icon: DeleteIcon,
onClick: () => onDelete(),
},