Tons of minor fixes

This commit is contained in:
Frikky
2025-10-21 00:34:57 +02:00
parent 23a6b4eff3
commit d26b7779e1
15 changed files with 463 additions and 141 deletions
+2 -2
View File
@@ -476,7 +476,7 @@ const LoginPage = props => {
return;
}
window.location.pathname = "/workflows"
window.location.pathname = "/new-dashboard"
}, 2000);
}
@@ -658,7 +658,7 @@ const LoginPage = props => {
}
}
window.location.pathname = "/workflows"
window.location.pathname = "/new-dashboard"
}, 2000);
}
})
+96 -37
View File
@@ -10,22 +10,31 @@ import {
Divider,
Select,
MenuItem,
Tooltip,
CircularProgress,
} from '@mui/material';
import TrendingUpIcon from '@mui/icons-material/TrendingUp';
import TrendingDownIcon from '@mui/icons-material/TrendingDown';
import ErrorOutlineIcon from '@mui/icons-material/ErrorOutline';
import TaskAltIcon from '@mui/icons-material/TaskAlt';
import { toast } from "react-toastify";
import {
TrendingFlat as TrendingFlatIcon,
TrendingUp as TrendingUpIcon,
TrendingDown as TrendingDownIcon,
TaskAlt as TaskAltIcon,
SuccessFailed as SuccessFailedIcon,
RunsOverTime as RunsOverTimeIcon,
ErrorOutline as ErrorOutlineIcon,
} from '@mui/icons-material';
import SuccessFailedRunsWidget from '../components/SuccessFailedRunsWidget.jsx';
import RunsOverTimeWidget from '../components/RunsOverTimeWidget.jsx';
import { Context } from '../context/ContextApi.jsx';
import CircularProgress from '@mui/material/CircularProgress';
import { useNavigate } from 'react-router-dom';
import DashboardOnboarding from '../components/DashboardOnboarding.jsx';
import { Context } from '../context/ContextApi.jsx';
import { useNavigate } from 'react-router-dom';
const NewDashboard = (props) => {
const { globalUrl, userdata } = props;
const { globalUrl, serverside, userdata } = props;
// const [workflows, setWorkflows] = useState([]);
const { leftSideBarOpenByClick } = useContext(Context);
const [sfwControls, setSfwControls] = useState(null);
const [loadingSfw, setLoadingSfw] = useState(true);
@@ -40,9 +49,18 @@ const NewDashboard = (props) => {
} catch {
return true;
}
});
})
const [overrideDays, setOverrideDays] = useState(undefined);
const [rotMonthOverride, setRotMonthOverride] = useState(undefined);
const [isProdStatusOn, setIsProdStatusOn] = useState(false)
const isCloud =
serverside === true || typeof window === "undefined"
? true
: window.location.host === "localhost:3002" ||
window.location.host === "shuffler.io" ||
window.location.host === "localhost:5002";
const navigate = useNavigate();
const handleSfwControls = useCallback((node) => {
@@ -71,8 +89,6 @@ const NewDashboard = (props) => {
};
const timeFmt = formatTimeDisplay(totals.timeSavedMinutes);
const STATIC_TIME_PERCENT = '62%';
const STATIC_MONEY_PERCENT = '46%';
const unreadCount = notifications.filter(n => n && n.read === false).length;
const readCount = notifications.filter(n => n && n.read === true).length;
@@ -81,9 +97,11 @@ const NewDashboard = (props) => {
// 1 Workflow run = 15 minutes
// 1 Workflow run = $25
const STATIC_TIME_PERCENT = 'TBD'
const STATIC_MONEY_PERCENT = 'TBD'
const kpis = [
{ value: timeFmt.display, title: timeFmt.title, label: 'Time saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_TIME_PERCENT, color: '#5cc879' },
{ value: formatCurrencyCompact(totals.moneySavedDollars), label: 'Money saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_MONEY_PERCENT, color: '#5cc879' },
{ value: timeFmt.display, title: timeFmt.title, label: 'Time saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_TIME_PERCENT, color: '#5cc879', disabled: true},
{ value: formatCurrencyCompact(totals.moneySavedDollars), label: 'Money saved', icon: <TrendingUpIcon sx={{ color: '#5cc879', fontSize: 34 }} />, percentage: STATIC_MONEY_PERCENT, color: '#5cc879', disabled: true, },
{ value: String(unreadCount), label: 'Total errors', icon: <ErrorOutlineIcon sx={{ color: '#f87171', fontSize: 34, opacity: 0.9 }} />, percentage: "", color: '#f87171' },
{ value: String(readCount), label: 'Errors resolved', icon: <TaskAltIcon sx={{ color: '#5cc879', fontSize: 34, opacity: 0.9 }} />, percentage: "", color: '#5cc879' },
];
@@ -177,13 +195,51 @@ const NewDashboard = (props) => {
// loadWorkflows();
// }, [globalUrl]);
useEffect(() => {
const orgId = userdata?.active_org?.id;
if (!orgId) {
return;
}
let fetched = false;
fetch(`${globalUrl}/api/v1/orgs/${orgId}`, {
method: "GET",
credentials: "include",
headers: { "Content-Type": "application/json" },
})
.then((response) => (response.ok ? response.json() : null))
.then((org) => {
if (!fetched && org) {
if (!isCloud) {
if (org?.cloud_sync && org?.subscriptions[0]?.name?.toLowerCase().includes("enterprise") && org?.subscriptions[0]?.active) {
setIsProdStatusOn(true);
} else if (org?.subscriptions[0]?.name?.toLowerCase().includes("enterprise") && org?.subscriptions[0]?.active) {
setIsProdStatusOn(true);
} else {
setIsProdStatusOn(false);
}
}
}
})
.catch(() => {});
return () => {
fetched = true;
};
}, [userdata?.active_org?.id, globalUrl]);
return (
<div style={{ maxWidth: 1366, margin: '0 auto', padding: 16, paddingTop: 50, paddingBottom: 30, paddingLeft: leftSideBarOpenByClick ? 270 : 80, transition: 'padding-left 0.3s ease', position: 'relative' }}>
<DashboardOnboarding
open={onboardingOpen}
globalUrl={globalUrl}
onClose={() => setOnboardingOpen(false)}
onClose={() => {
setOnboardingOpen(false)
}}
setOnboardingOpen={setOnboardingOpen}
isProdStatusOn={isProdStatusOn}
isCloud={isCloud}
onExplore={() => {
// Ensure overrides are set before closing modal
setOverrideDays(5);
@@ -215,28 +271,31 @@ const NewDashboard = (props) => {
<Grid container spacing={2}>
{kpis.map((kpi) => (
<Grid item xs={12} sm={6} md={3} key={kpi.label}>
<Paper style={{ padding: 16, background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 12
,cursor: kpi.label.toLowerCase().includes('total errors') ? 'pointer' : 'default'
}}
onClick={() => {
if (kpi.label.toLowerCase().includes('total errors')) {
// navigate to notifications page
navigate('/admin?admin_tab=notifications');
}
}}
>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Stack sx={{py:2, paddingLeft: 1}}>
<Typography variant="h4" title={kpi.title || ''}>{kpi.value}</Typography>
<Typography sx={{fontSize: 13}} color="textSecondary">{kpi.label}</Typography>
</Stack>
<Stack sx={{py: 2, paddingRight: 1, marginTop: kpi.label.toLowerCase().includes('errors') ? -1 : 0}}>
{kpi.icon}
<Typography variant="body2" color={kpi.color}>{kpi.percentage}</Typography>
</Stack>
</Stack>
</Paper>
<Tooltip title={kpi.disabled ? "This metric is coming soon!" : ""} arrow>
<Paper style={{ padding: 16, background: 'rgba(255,255,255,0.03)', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 12
, cursor: kpi.label.toLowerCase().includes('total errors') ? 'pointer' : 'default',
transparency: kpi.disabled ? 0.5 : 1
}}
onClick={() => {
if (kpi.label.toLowerCase().includes('total errors')) {
// navigate to notifications page
navigate('/admin?admin_tab=notifications');
}
}}
>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Stack sx={{py:2, paddingLeft: 1}}>
<Typography variant="h4" title={kpi.title || ''}>{kpi.value}</Typography>
<Typography sx={{fontSize: 13}} color="textSecondary">{kpi.label}</Typography>
</Stack>
<Stack sx={{py: 2, paddingRight: 1, marginTop: kpi.label.toLowerCase().includes('errors') ? -1 : 0}}>
{kpi.icon}
<Typography variant="body2" color={kpi.color}>{kpi.percentage}</Typography>
</Stack>
</Stack>
</Paper>
</Tooltip>
</Grid>
))}
</Grid>
+104 -2
View File
@@ -818,6 +818,7 @@ const Workflows2 = (props) => {
const [highlightIds, setHighlightIds] = React.useState([])
const [apps, setApps] = React.useState([]);
const [isProdStatusOn, setIsProdStatusOn] = React.useState(false);
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
@@ -839,6 +840,39 @@ const Workflows2 = (props) => {
}
}, [location.search]);
useEffect(() => {
const orgId = userdata?.active_org?.id;
if (!orgId) {
return;
}
let fetched = false;
fetch(`${globalUrl}/api/v1/orgs/${orgId}`, {
method: "GET",
credentials: "include",
headers: { "Content-Type": "application/json" },
})
.then((response) => (response.ok ? response.json() : null))
.then((org) => {
if (!fetched && org) {
if (!isCloud) {
if (org?.cloud_sync && org?.subscriptions[0]?.name?.toLowerCase().includes("enterprise") && org?.subscriptions[0]?.active) {
setIsProdStatusOn(true);
} else if (org?.subscriptions[0]?.name?.toLowerCase().includes("enterprise") && org?.subscriptions[0]?.active) {
setIsProdStatusOn(true);
} else {
setIsProdStatusOn(false);
}
}
}
})
.catch(() => {});
return () => {
fetched = true;
};
}, [userdata?.active_org?.id, globalUrl]);
const handleTabChange = (event, newValue) => {
setCurrTab(newValue);
@@ -3043,12 +3077,34 @@ const Workflows2 = (props) => {
}
}
const isPublicWorkflow = data?.objectId === undefined || data?.objectId === null
const foundImage = !isPublicWorkflow ? "" : data?.image_url === undefined || data?.image_url === null || data?.image_url === "" ? data?.image : data?.image_url
const foundTimeline = workflowTimelines.find((timeline) => timeline.id === data.id)
return (
<div
id={`workflowbox-${data.id}`}
style={{ width: "100%", minWidth: 320, position: "relative", border: highlightIds.includes(data.id) ? "2px solid #f85a3e" : isDistributed || hasSuborgs ? `2px solid ${theme.palette.distributionColor}` : "inherit", borderRadius: theme.palette?.borderRadius, backgroundColor: "#212121", fontFamily: theme.typography?.fontFamily }}>
style={{ width: "100%", minWidth: 320, position: "relative", border: highlightIds.includes(data.id) ? "2px solid #f85a3e" : isDistributed || hasSuborgs ? `2px solid ${theme.palette.distributionColor}` : "inherit", borderRadius: theme.palette?.borderRadius, backgroundColor: "#212121", fontFamily: theme.typography?.fontFamily, overflow: "hidden", }}
>
{isPublicWorkflow && foundImage?.length > 0 ?
<img src={foundImage} alt="image" style={{
maxHeight: 250,
minHeight: 250,
minWidth: 100,
marginLeft: 12,
cursor: "pointer",
}}
onClick={() => {
if (isCloud) {
navigate(`/workflows/${data.objectID}`)
} else {
window.open(`https://shuffler.io/workflows/${data.objectID}`, "_blank")
}
}}
/>
: null}
<Paper square style={paperAppStyle}>
{selectedCategory !== "" ?
<Tooltip title={`Usecase Category: ${selectedCategory}`} placement="bottom">
@@ -4934,7 +4990,7 @@ const Workflows2 = (props) => {
}}
/>
<Tab
label="Discover Workflows"
label="Community Workflows"
style={{
...tabStyle,
marginRight: 0,
@@ -5313,12 +5369,58 @@ const Workflows2 = (props) => {
</div>
}
{!isCloud ? (
<div
style={{
display: "flex",
alignItems: "center",
gap: 20,
padding: "4px 10px",
marginLeft: "5px",
marginRight: "5px",
borderRadius: 20,
marginBottom: "14px",
background: isProdStatusOn
? "rgba(43, 192, 126, 0.1)"
: "rgba(255, 82, 82, 0.1)",
cursor: "pointer",
position: "absolute",
top: 20,
right: 20,
}}
onClick={() => {
navigate("/admin?admin_tab=billingstats")
}}
>
<span
style={{
width: 8,
height: 8,
marginLeft: 10,
background: isProdStatusOn ? "#2BC07E" : "#FD4C62",
borderRadius: 999,
display: "inline",
}}
/>
<Typography
style={{
fontFamily: "12px",
opacity: 0.9,
color: isProdStatusOn ? "#2BC07E" : "#FD4C62",
}}
>
{isProdStatusOn ? "Production" : "NOT Production"}
</Typography>
</div>
) : null}
<div style={{
width: "100%",
position: "relative",
zIndex: 1
}}>
{
(isLoadingWorkflow && currTab !== 2) ? (
<LoadingWorkflowGrid />