Lightmode/Darkmode merge including many fixes since 2.0.2

This commit is contained in:
Frikky
2025-05-19 00:04:37 +02:00
parent 7bc246c003
commit a4ebf3e558
59 changed files with 5931 additions and 2961 deletions
+256 -26
View File
@@ -19,17 +19,97 @@ import {
FmdGoodOutlined as FmdGoodOutlinedIcon,
GroupOutlined as GroupOutlinedIcon
} from '@mui/icons-material';
import theme from '../theme.jsx';
import { Button, Tooltip } from '@mui/material';
import theme, { getTheme } from '../theme.jsx';
import { Button, Skeleton, Tooltip } from '@mui/material';
import { Index } from 'react-instantsearch-dom';
import { Context } from '../context/ContextApi.jsx';
import { toast } from 'react-toastify';
const AdminNavBar = (props) => {
const location = useLocation();
const { globalUrl, userdata, isCloud, isLoaded,removeCookie, handleStatusChange, selectedStatus, setSelectedStatus, handleEditOrg, serverside, notifications, handleGetOrg, orgId, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } = props;
const { globalUrl, userdata, isCloud,isOrgLoaded, isLoaded,removeCookie, handleStatusChange, selectedStatus, setSelectedStatus, handleEditOrg, serverside, notifications, handleGetOrg, orgId, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } = props;
const [selectedItem, setSelectedItem] = useState("Organization");
const [isSelectedFiles, setIsSelectedFiles] = useState(true);
const [isSelectedDataStore, setIsSelectedDataStore] = useState(true);
const [isIntegrationPartner, setIsIntegrationPartner] = useState(false);
const [isChildOrg, setIsChildOrg] = useState(false);
const [isGlobalUser, setIsGlobalUser] = useState(false);
const [visibleItems, setVisibleItems] = useState([]);
const [isUserDataLoaded, setIsUserDataLoaded] = useState(false);
const items = [
{ iconSrc: <BusinessIcon />, alt: "Organization Icon", text: "Organization", component: OrganizationTab, props: { isIntegrationPartner, isChildOrg, isGlobalUser, globalUrl,removeCookie, selectedStatus, isLoaded, setSelectedStatus, handleStatusChange, handleEditOrg, handleGetOrg, userdata, isCloud, serverside, notifications, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } },
{ iconSrc: <PermIdentityIcon />, alt: "Users Icon", text: "Users", component: UserManagmentTab, props: { globalUrl, userdata, serverside, isCloud, selectedOrganization, setSelectedOrganization, handleEditOrg } },
{ iconSrc: <HttpsOutlinedIcon />, alt: "App Auth Icon", text: "App_auth", component: AppAuthTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
{ iconSrc: <StorageOutlinedIcon />, alt: "Datastore Icon", text: "Datastore", component: CacheView, props: { globalUrl, userdata, selectedOrganization, serverside, isSelectedDataStore, orgId , isCloud} },
{ iconSrc: <InsertDriveFileOutlinedIcon />, alt: "Files Icon", text: "Files", component: Files, props: { isCloud, globalUrl, userdata, serverside, selectedOrganization, isSelectedFiles } },
{ iconSrc: <AccessTimeOutlinedIcon />, alt: "Trigger Icon", text: "Triggers", component: SchedulesTab, props: { globalUrl, userdata, isCloud, serverside } },
{ iconSrc: <FmdGoodOutlinedIcon />, alt: "Environments Icon", text: "Locations", component: EnvironmentTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
{ iconSrc: <GroupOutlinedIcon />, alt: "Tenants Icon", text: "Tenants", component: TenantsTab, props: {isCloud, globalUrl, userdata, serverside, selectedOrganization, setSelectedOrganization, checkLogin } }
];
useEffect(() => {
if (userdata && userdata?.active_org?.id?.length > 0) {
setIsUserDataLoaded(true);
}
}, [userdata]);
const { themeMode, brandColor } = React.useContext(Context);
const theme = getTheme(themeMode, brandColor);
const HandlePartnerChange = () => {
if (userdata?.id?.length > 0) {
const isIntegrationPartner = userdata?.org_status?.includes("integration_partner") || false;
setIsIntegrationPartner(isIntegrationPartner);
const isChildOrg = userdata?.org_status?.includes("sub_org") || false;
setIsChildOrg(isChildOrg);
const isGlobalUser = userdata?.active_org?.branding?.global_user || false;
setIsGlobalUser(isGlobalUser);
} else {
setIsIntegrationPartner(false);
setIsChildOrg(false);
setIsGlobalUser(false);
}
}
useEffect(() => {
if (userdata && userdata?.id?.length > 0) {
HandlePartnerChange();
}
}, [userdata]);
const HandleVisibleTabs = () => {
if (userdata?.id?.length > 0) {
if (userdata?.active_org?.role === "admin" || userdata?.support) {
setVisibleItems(items);
}else {
const filteredItems = items.filter(item => item.text !== "Users" && item.text !== "Files" && item.text !== "Datastore" && item.text !== "Triggers" && item.text !== "Locations");
setVisibleItems(filteredItems);
}
}
}
useEffect(() => {
if (isIntegrationPartner && isChildOrg && !isGlobalUser) {
// Filter out Users and Tenants tabs
if (userdata?.active_org?.role === "admin" || userdata?.support) {
const filteredItems = items.filter(item =>
item.text !== "Users" && item.text !== "Tenants"
);
setVisibleItems(filteredItems);
}else {
const filteredItems = items.filter(item =>
item.text !== "Users" && item.text !== "Tenants" && item.text !== "Files" && item.text !== "Datastore" && item.text !== "Triggers" && item.text !== "Locations"
);
setVisibleItems(filteredItems);
}
} else {
HandleVisibleTabs();
}
}, [isIntegrationPartner, isChildOrg, isGlobalUser, selectedOrganization, userdata]);
const navigate = useNavigate();
@@ -52,18 +132,6 @@ const AdminNavBar = (props) => {
setSelectedItem("Organization");
}
}, [location.search]);
const items = [
{ iconSrc: <BusinessIcon />, alt: "Organization Icon", text: "Organization", component: OrganizationTab, props: { globalUrl,removeCookie, selectedStatus, isLoaded, setSelectedStatus, handleStatusChange, handleEditOrg, handleGetOrg, userdata, isCloud, serverside, notifications, checkLogin, setNotifications, stripeKey, setSelectedOrganization, selectedOrganization } },
{ iconSrc: <PermIdentityIcon />, alt: "Users Icon", text: "Users", component: UserManagmentTab, props: { globalUrl, userdata, serverside, isCloud, selectedOrganization, setSelectedOrganization, handleEditOrg } },
{ iconSrc: <HttpsOutlinedIcon />, alt: "App Auth Icon", text: "App_auth", component: AppAuthTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
{ iconSrc: <StorageOutlinedIcon />, alt: "Datastore Icon", text: "Datastore", component: CacheView, props: { globalUrl, userdata, selectedOrganization, serverside, isSelectedDataStore, orgId , isCloud} },
{ iconSrc: <InsertDriveFileOutlinedIcon />, alt: "Files Icon", text: "Files", component: Files, props: { isCloud, globalUrl, userdata, serverside, selectedOrganization, isSelectedFiles } },
{ iconSrc: <AccessTimeOutlinedIcon />, alt: "Trigger Icon", text: "Triggers", component: SchedulesTab, props: { globalUrl, userdata, isCloud, serverside } },
{ iconSrc: <FmdGoodOutlinedIcon />, alt: "Environments Icon", text: "Locations", component: EnvironmentTab, props: { globalUrl, userdata, isCloud, selectedOrganization } },
{ iconSrc: <GroupOutlinedIcon />, alt: "Tenants Icon", text: "Tenants", component: TenantsTab, props: {isCloud, globalUrl, userdata, serverside, selectedOrganization, setSelectedOrganization, checkLogin } }
];
const setConfig = (newValue) => {
setSelectedItem(newValue);
@@ -76,12 +144,65 @@ const AdminNavBar = (props) => {
}
};
useEffect(() => {
if (isIntegrationPartner && isChildOrg && !isGlobalUser && isOrgLoaded && isUserDataLoaded) {
const queryParams = new URLSearchParams(location.search);
const tabName = queryParams?.get('admin_tab')?.toLowerCase();
if (tabName === "sso" || tabName === "branding") {
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
setTimeout(() => {
setSelectedItem("Organization");
navigate(`?admin_tab=org_config`, { replace: true });
window.location.reload();
}
, 3000);
}
const params = new URLSearchParams(location.search);
const tab = params?.get('tab')?.toLowerCase();
if (tab === "users" || tab === "tenants") {
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
setTimeout(() => {
setSelectedItem("Organization");
navigate(`?admin_tab=org_config`, { replace: true });
window.location.reload();
}
, 3000);
}
} else if (userdata && isOrgLoaded && isUserDataLoaded && userdata?.active_org?.role !== "admin" && !userdata?.support) {
const queryParams = new URLSearchParams(location.search);
const tabName = queryParams?.get('admin_tab')?.toLowerCase();
if (tabName === "sso") {
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
setTimeout(() => {
setSelectedItem("Organization");
navigate(`?admin_tab=org_config`, { replace: true });
window.location.reload();
}
, 3000);
}
const params = new URLSearchParams(location.search);
const tab = params?.get('tab')?.toLowerCase();
if (tab === "users" || tab === "locations" || tab === "environments" || tab === "files" || tab === "datastore" || tab === "triggers") {
toast.info("You are not allowed to access this tab. Please contact your admin for more information. Redirecting to Organization Configuration tab.");
setTimeout(() => {
setSelectedItem("Organization");
navigate(`?admin_tab=org_config`, { replace: true });
window.location.reload();
}
, 3000);
}
}
}, [isIntegrationPartner, isChildOrg, isGlobalUser, location.search, userdata, isOrgLoaded, isUserDataLoaded]);
const renderComponent = () => {
const selectedItemData = items.find(item => item.text === selectedItem);
const selectedItemData = visibleItems.find(item => item.text === selectedItem);
if (!selectedItemData) {
setSelectedItem("Organization");
// If no tab is specified, default to "Organization" tab
return <OrganizationTab globalUrl={globalUrl} removeCookie={removeCookie} selectedStatus={selectedStatus} isLoaded={isLoaded} setSelectedStatus={setSelectedStatus} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} userdata={userdata} isCloud={isCloud} serverside={serverside} notifications={notifications} checkLogin={checkLogin} setNotifications={setNotifications} stripeKey={stripeKey} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization}/>;
return <OrganizationTab isIntegrationPartner={isIntegrationPartner} isChildOrg={isChildOrg} isGlobalUser={isGlobalUser} globalUrl={globalUrl} removeCookie={removeCookie} selectedStatus={selectedStatus} isLoaded={isLoaded} setSelectedStatus={setSelectedStatus} handleStatusChange={handleStatusChange} handleEditOrg={handleEditOrg} handleGetOrg={handleGetOrg} userdata={userdata} isCloud={isCloud} serverside={serverside} notifications={notifications} checkLogin={checkLogin} setNotifications={setNotifications} stripeKey={stripeKey} setSelectedOrganization={setSelectedOrganization} selectedOrganization={selectedOrganization}/>;
};
const ComponentToRender = selectedItemData.component;
@@ -97,15 +218,16 @@ const AdminNavBar = (props) => {
: selectedOrganization?.image;
return (
!isOrgLoaded && !isUserDataLoaded ? <Loader /> :
<Wrapper>
<div style={{ flexDirection: 'column', width: 220, }}>
<nav style={{ padding: '25px 25px 3px 25px', height: isCloud ? "calc(100% - 60px)" : "calc(100% - 30px)" , fontSize: '16px', borderTopLeftRadius: 8, borderBottomLeftRadius: 8, background: '#212121', color: '#9CA3AF' }}>
<nav style={{ padding: '25px 25px 3px 25px', height: isCloud ? "calc(100% - 60px)" : "calc(100% - 30px)" , fontSize: '16px', borderTopLeftRadius: 8, borderBottomLeftRadius: 8, background: theme.palette.platformColor, color: '#9CA3AF' }}>
<div style={{ display: 'flex', alignItems: 'center', }}>
<img loading="lazy" src={imageData} alt="Logo" style={{ width: '30px', borderRadius: 8, height: '30px', marginRight: '8px' }} />
<div style={{
fontFamily: theme?.typography?.fontFamily,
fontSize: '16px',
color: "#FFFFFF",
color: theme.palette.text.primary,
fontWeight: 400,
overflow: 'hidden',
textOverflow: 'ellipsis',
@@ -114,8 +236,8 @@ const AdminNavBar = (props) => {
marginLeft: 5,
}}>{selectedOrganization?.name}</div>
</div>
<div style={{ borderTop: '1px solid #494949', marginTop: 23 }} />
{items.map((item, index) => (
<div style={{ borderTop: theme.palette.defaultBorder, marginTop: 23 }} />
{visibleItems.map((item, index) => (
<Tooltip
key={index}
title={
@@ -132,11 +254,10 @@ const AdminNavBar = (props) => {
color="primary"
sx={{
gap: 1,
"&:hover": {
backgroundColor: "#323232 !important",
},
"&.MuiButton-root": {
color: selectedItem === item.text ? "#FFFFFF" : "#9E9E9E",
color: selectedItem === item.text
? theme.palette.text.primary
: theme.palette.text.secondary,
fontSize: 16,
backgroundColor: "transparent",
textTransform: "none",
@@ -149,13 +270,16 @@ const AdminNavBar = (props) => {
justifyContent: "flex-start",
borderLeft:
selectedItem === item.text
? "3px solid rgba(255, 132, 68, 1)"
? `3px solid ${theme.palette.primary.main}`
: "none",
borderTopLeftRadius: selectedItem === item.text ? "2.5px" : null,
borderBottomLeftRadius: selectedItem === item.text ? "2.5px" : null,
paddingLeft: selectedItem === item.text ? "15px" : "10px",
fontWeight: selectedItem === item.text ? 200 : "normal",
flex: 1,
"&:hover": {
backgroundColor: theme.palette.hoverColor,
},
},
"&.Mui-disabled": {
color: "#6F6F6F",
@@ -183,6 +307,112 @@ const AdminNavBar = (props) => {
export default AdminNavBar;
const Loader = () => {
const dummyItems = Array.from({ length: 6 });
const dummyNavItems = Array.from({ length: 6 });
const dummyTabItems = ['Org Configuration', 'SSO', 'Notifications', 'Billing & Stats', 'Branding'];
const { leftSideBarOpenByClick, windowWidth, themeMode } = useContext(Context);
const theme = getTheme(themeMode);
return (
<div style={{
display: 'flex',
width: '100%',
height: '100%',
minHeight: '100vh',
maxWidth: '1200px',
fontFamily: 'Arial, sans-serif',
paddingLeft: leftSideBarOpenByClick ? windowWidth <= 1300 ? 220 : 200 : 80,
transition: "padding-left 0.3s ease",
}}>
<div style={{
width: '220px',
backgroundColor: theme.palette.platformColor,
borderTopLeftRadius: '8px',
borderBottomLeftRadius: '8px',
padding: '25px 25px 3px 25px',
display: 'flex',
flexDirection: 'column'
}}>
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '20px' }}>
<Skeleton
width="30px"
height="30px"
sx={{ borderRadius: '8px', marginRight: '8px', }}
/>
<Skeleton width="120px" height="24px" />
</div>
{/* Divider */}
<Skeleton
width="100%"
height="1px"
sx={{ marginBottom: '15px' }}
/>
{/* Nav Items */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '5px', width: '100%' }}>
{dummyNavItems.map((_, index) => (
<div key={index} style={{ display: 'flex', alignItems: 'center', padding: '5px 0' }}>
<Skeleton
width="18px"
height="18px"
sx={{ marginRight: '10px' }}
/>
<Skeleton width={`${100 + Math.random() * 40}px`} height="36px" />
</div>
))}
</div>
</div>
<div style={{
flex: 1,
backgroundColor: theme.palette.platformColor,
borderTopRightRadius: '8px',
borderBottomRightRadius: '8px',
borderLeft: theme.palette.defaultBorder,
display: 'flex',
flexDirection: 'column'
}}>
<div style={{
display: 'flex',
borderBottom: theme.palette.defaultBorder,
padding: '0 16px'
}}>
{dummyTabItems.map((_, index) => (
<div
key={index}
style={{
flex: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '28px 0',
borderBottom: index === 0 ? '2px solid #FF8444' : 'none'
}}
>
<Skeleton width={`${80 + Math.random() * 30}px`} height="24px" />
</div>
))}
</div>
<div style={{ flex: 1, padding: '24px' }}>
<div style={{ display: 'flex', flexDirection: 'column', width: '100%', margin: '0 auto', alignItems: 'flex-start' }}>
<Skeleton variant='square' width="200px" height="200px" sx={{ marginBottom: '20px' }} />
<div style={{ display: 'flex', flexDirection: 'column', gap: '10px', width: '100%', marginTop: '50px' }}>
{dummyItems.map((_, index) => (
<div key={index} style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
<Skeleton width={'400px'} height="36px" />
</div>
))}
</div>
</div>
</div>
</div>
</div>
);
};
const PaddingWrapper2 = memo(({ children }) => {
return (