Added the filtered search and categories dropdown

This commit is contained in:
monilprajapati
2024-11-29 09:59:44 +05:30
parent 8272fdf6b6
commit 99c6c31dd0
+180 -92
View File
@@ -647,7 +647,8 @@ const Workflows2 = (props) => {
const [selectedCategory, setSelectedCategory] = useState([]); const [selectedCategory, setSelectedCategory] = useState([]);
const [selectedLabel, setSelectedLabel] = useState([]); const [selectedLabel, setSelectedLabel] = useState([]);
const [mouseHoverIndex, setMouseHoverIndex] = useState(-1); const [mouseHoverIndex, setMouseHoverIndex] = useState(-1);
const [isLoading, setIsLoading] = useState(false); const [isLoadingWorkflow, setIsLoadingWorkflow] = useState(false);
const [isLoadingPublicWorkflow, setIsLoadingPublicWorkflow] = useState(false);
const [view, setView] = useState("grid"); const [view, setView] = useState("grid");
const classes = useStyles(theme) const classes = useStyles(theme)
const imgSize = 60; const imgSize = 60;
@@ -710,6 +711,15 @@ const Workflows2 = (props) => {
document.title = "Shuffle - Workflows"; document.title = "Shuffle - Workflows";
const handleTabChange = (event, newValue) => { const handleTabChange = (event, newValue) => {
// Set loading when switching to public workflows tab
if (newValue === 2) {
setIsLoadingPublicWorkflow(true);
// Simulate loading time for the Algolia search results
setTimeout(() => {
setIsLoadingPublicWorkflow(false);
}, 2000);
}
setCurrTab(newValue); setCurrTab(newValue);
}; };
@@ -2044,42 +2054,42 @@ const Workflows2 = (props) => {
}; };
const getWorkflowAppgroup = (data) => { const getWorkflowAppgroup = (data) => {
if(currTab !== 2){ if (currTab !== 2) {
if (data.actions === undefined || data.actions === null) { if (data.actions === undefined || data.actions === null) {
return [] return []
} }
var appsFound = [] var appsFound = []
for (var key in data.actions) { for (var key in data.actions) {
const parsedAction = data.actions[key] const parsedAction = data.actions[key]
if (parsedAction.large_image === undefined || parsedAction.large_image === null || parsedAction.large_image === "") { if (parsedAction.large_image === undefined || parsedAction.large_image === null || parsedAction.large_image === "") {
continue continue
} }
if (parsedAction.app_name === "Shuffle Tools" || parsedAction.app_id === "bc78f35c6c6351b07a09b7aed5d29652") { if (parsedAction.app_name === "Shuffle Tools" || parsedAction.app_id === "bc78f35c6c6351b07a09b7aed5d29652") {
continue continue
} }
if (appsFound.findIndex(data => data.app_name === parsedAction.app_name) < 0) { if (appsFound.findIndex(data => data.app_name === parsedAction.app_name) < 0) {
appsFound.push(parsedAction) appsFound.push(parsedAction)
} }
} }
}else{ } else {
if (data.action_references === undefined || data.action_references === null) { if (data.action_references === undefined || data.action_references === null) {
return [] return []
} }
var appsFound = [] var appsFound = []
for (var key in data.action_references) { for (var key in data.action_references) {
const parsedAction = data.action_references[key] const parsedAction = data.action_references[key]
if (parsedAction.image_url === undefined || parsedAction.image_url === null || parsedAction.image_url === "") { if (parsedAction.image_url === undefined || parsedAction.image_url === null || parsedAction.image_url === "") {
continue continue
} }
if (parsedAction.name === "Shuffle Tools" || parsedAction.id === "3e2bdf9d5069fe3f4746c29d68785a6a") { if (parsedAction.name === "Shuffle Tools" || parsedAction.id === "bc78f35c6c6351b07a09b7aed5d29652") {
continue continue
} }
if (appsFound.findIndex(data => data.name === parsedAction.name) < 0) { if (appsFound.findIndex(data => data.name === parsedAction.name) < 0) {
appsFound.push(parsedAction) appsFound.push(parsedAction)
} }
@@ -2090,7 +2100,7 @@ const Workflows2 = (props) => {
} }
const WorkflowPaper = (props) => { const WorkflowPaper = (props) => {
const { data, type="org" } = props; const { data, type = "org" } = props;
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [anchorEl, setAnchorEl] = React.useState(null); const [anchorEl, setAnchorEl] = React.useState(null);
@@ -2120,7 +2130,6 @@ const Workflows2 = (props) => {
const actions = data.actions !== null ? data.actions.length : 0; const actions = data.actions !== null ? data.actions.length : 0;
const appGroup = getWorkflowAppgroup(data) const appGroup = getWorkflowAppgroup(data)
console.log("appgroup", appGroup)
const [triggers, subflows] = getWorkflowMeta(data) const [triggers, subflows] = getWorkflowMeta(data)
const hasSuborgs = data.suborg_distribution !== undefined && data.suborg_distribution !== null && data.suborg_distribution.length > 0 const hasSuborgs = data.suborg_distribution !== undefined && data.suborg_distribution !== null && data.suborg_distribution.length > 0
@@ -2242,7 +2251,7 @@ const Workflows2 = (props) => {
); );
var image = ""; var image = "";
var orgName = ""; var orgName = "";
var orgId = ""; var orgId = "";
if (userdata.orgs !== undefined) { if (userdata.orgs !== undefined) {
@@ -2366,9 +2375,9 @@ const Workflows2 = (props) => {
*/ */
}} }}
title={ title={
<div style={{ <div style={{
width: "100%", width: "100%",
minWidth: 250, minWidth: 250,
maxWidth: 310, maxWidth: 310,
padding: "12px 0", padding: "12px 0",
}}> }}>
@@ -2379,25 +2388,25 @@ const Workflows2 = (props) => {
overflow: "hidden", overflow: "hidden",
border: `1px solid ${theme.palette.inputColor}`, border: `1px solid ${theme.palette.inputColor}`,
}}> }}>
<img <img
src={data.image} src={data.image}
alt={data.name} alt={data.name}
style={{ style={{
backgroundColor: theme.palette.surfaceColor, backgroundColor: theme.palette.surfaceColor,
width: "100%", width: "100%",
height: "auto", height: "auto",
display: "block", display: "block",
}} }}
/> />
</div> </div>
) : null} ) : null}
<Typography style={{ <Typography style={{
color: "rgba(255,255,255,0.9)", color: "rgba(255,255,255,0.9)",
}}> }}>
Edit: {data.name} Edit: {data.name}
</Typography> </Typography>
{(isDistributed || hasSuborgs) && ( {(isDistributed || hasSuborgs) && (
<div style={{ <div style={{
backgroundColor: "rgba(64,224,208,0.1)", // Matching the teal color used in border backgroundColor: "rgba(64,224,208,0.1)", // Matching the teal color used in border
@@ -3269,7 +3278,7 @@ const Workflows2 = (props) => {
}} }}
> >
<DialogTitle style={{ padding: "20px 24px" }}> <DialogTitle style={{ padding: "20px 24px" }}>
<div style={{ <div style={{
color: "rgba(255,255,255,0.9)", color: "rgba(255,255,255,0.9)",
display: "flex", display: "flex",
justifyContent: "space-between", justifyContent: "space-between",
@@ -3780,31 +3789,42 @@ const Workflows2 = (props) => {
// } // }
useEffect(() => { useEffect(() => {
console.log("CurrTab: ", currTab)
console.log("Workflows: ", workflows)
if (userdata !== undefined && userdata !== null) { if (userdata !== undefined && userdata !== null) {
var filteredWorkflows = []
setIsLoadingWorkflow(true);
if (currTab === 0) { if (currTab === 0) {
const orgWorkflows = workflows.filter(workflow => workflow?.org_id === userdata?.active_org?.id) filteredWorkflows = workflows.filter(workflow => workflow?.org_id === userdata?.active_org?.id)
setFilteredWorkflows(orgWorkflows)
} }
else if (currTab === 1) { else if (currTab === 1) {
const myWorkflows = workflows.filter(workflow => workflow?.org_id === userdata?.active_org?.id && workflow?.owner === userdata?.id) filteredWorkflows = workflows.filter(workflow => workflow?.org_id === userdata?.active_org?.id && workflow?.owner === userdata?.id)
setFilteredWorkflows(myWorkflows)
} }
} else { setFilteredWorkflows(filteredWorkflows)
setFilteredWorkflows([]) setIsLoadingWorkflow(false);
} }
}, [currTab, workflows, userdata]) }, [currTab, workflows, userdata])
useEffect(() => {
console.log("SearchQuery: ", searchQuery)
}, [searchQuery])
const Hits = ({ hits }) => { const Hits = ({ hits }) => {
var counted = 0 var counted = 0
console.log("Public workflows", hits) console.log("Public workflows", hits)
if (isLoadingPublicWorkflow) {
return (
<div style={{ textAlign: "center", marginTop: 50 }}>
<CircularProgress style={{ color: "#f85a3e" }} />
</div>
);
}
return ( return (
<div style={{ <div style={{
display: "grid", display: "grid",
gridTemplateColumns: "repeat(3, 1fr)", // Creates 3 equal columns gridTemplateColumns: "repeat(3, 1fr)", // Creates 3 equal columns
gap: "20px", // Adds consistent spacing between items gap: "20px", // Adds consistent spacing between items
width: "100%", width: "100%",
}}> }}>
{hits.map((data, index) => { {hits.map((data, index) => {
return <WorkflowPaper key={index} data={data} type="public" /> return <WorkflowPaper key={index} data={data} type="public" />
@@ -3816,6 +3836,11 @@ const Workflows2 = (props) => {
const CustomHits = connectHits(Hits) const CustomHits = connectHits(Hits)
const handleCategoryChange = (e) => {
setSelectedCategory(e.target.value)
}
const WorkflowView = memo(() => { const WorkflowView = memo(() => {
if (workflows.length === 0) { if (workflows.length === 0) {
} }
@@ -4009,46 +4034,84 @@ const Workflows2 = (props) => {
</div> </div>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 20, gap: 10 }}> <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 20, gap: 10 }}>
<TextField
fullWidth <MuiChipsInput
placeholder="Filter Workflows"
variant="outlined" variant="outlined"
placeholder="Search workflows" color="primary"
value={searchQuery} value={filters}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(chips) => {
style={{ flex: 0.7, borderRadius: 8 }} console.log("CHANGE: ", chips);
InputProps={{ setFilters(chips);
style: { borderRadius: 8 }, findWorkflow(chips);
endAdornment: (
<InputAdornment position="end">
{searchQuery.length === 0 ? <Search /> :
<ClearIcon
style={{ cursor: 'pointer' }}
onClick={() => setSearchQuery('')}
/>
}
</InputAdornment>
),
}} }}
style={{ flex: 0.9, borderRadius: 8 }}
// style={searchStyle}
//onAdd={(chip) => {
// console.log("ADd: ", chip);
// addFilter(chip);
//}}
//onDelete={(_, index) => {
// console.log("Remove: ", index);
// removeFilter(index);
//}}
/> />
<Select <Select
fullWidth fullWidth
variant="outlined" variant="outlined"
value={selectedCategory} value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)} onChange={handleCategoryChange}
displayEmpty displayEmpty
multiple multiple
style={{ flex: 0.7, maxWidth: 300 }} style={{ flex: 0.9, maxWidth: 350, borderRadius: 8 }}
renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'} renderValue={(selected) => selected.length ? selected.join(', ') : 'All Categories'}
> >
<MenuItem disabled value="">All Categories</MenuItem> <MenuItem disabled value="">All Categories</MenuItem>
{/* Add category items here */} {usecases.map((usecase) => {
if (usecase?.name === "5. Verify") {
return null;
}
const percentDone = usecase.matches.length > 0 ? parseInt(usecase.matches.length / usecase.list.length * 100) : 0
if (percentDone === 0) {
usecase = findMatches(usecase, workflows)
}
const category = usecase?.name.split(" ")[1]
return (
<MenuItem value={category}
onClick={() => {
console.log("Filters: ", filters, usecase?.name.toLowerCase())
if (!filters.includes(usecase?.name.toLowerCase())) {
addFilter(usecase.name)
} else {
removeFilter(filters.indexOf(usecase?.name.toLowerCase()))
}
}}
>
<Checkbox checked={selectedCategory.includes(category)} />
<span style={{ textDecoration: "none", width: "100%", display: "flex", alignItems: "center", justifyContent: "space-between", paddingRight: 2 }}>
<Typography variant="body1" color="textPrimary">
{category}
</Typography>
<Typography variant="body2" color="textSecondary">
{usecase?.matches.length}/{usecase?.list.length}
</Typography>
</span>
</MenuItem>)
})}
</Select> </Select>
<div style={{ display: "flex", gap: 8, height: "100%" }}> <div style={{ display: "flex", gap: 8, height: "100%" }}>
<Tooltip title="Explore Workflow Runs" placement="top"> <Tooltip title="Explore Workflow Runs" placement="top">
<IconButton <IconButton
style={{ style={{
color: 'white', color: 'white',
backgroundColor: '#212121', backgroundColor: '#212121',
borderRadius: '8px', borderRadius: '8px',
@@ -4101,7 +4164,15 @@ const Workflows2 = (props) => {
{submitLoading ? <CircularProgress color="secondary" /> : <PublishIcon />} {submitLoading ? <CircularProgress color="secondary" /> : <PublishIcon />}
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="Download ALL workflows" placement="top"> <input
hidden
type="file"
multiple="multiple"
ref={(ref) => (upload = ref)}
onChange={importFiles}
/>
<Tooltip title={`Download ALL workflows (${workflows.length})`}
placement="top">
<IconButton <IconButton
style={{ style={{
color: 'white', color: 'white',
@@ -4111,7 +4182,11 @@ const Workflows2 = (props) => {
width: '55px', width: '55px',
height: '55px', height: '55px',
}} }}
onClick={() => {/* Add export handling */ }} disabled={isCloud}
variant="text"
onClick={() => {
exportAllWorkflows(workflows);
}}
> >
<GetAppIcon /> <GetAppIcon />
</IconButton> </IconButton>
@@ -4124,8 +4199,8 @@ const Workflows2 = (props) => {
onClick={handleCreateWorkflow} onClick={handleCreateWorkflow}
style={{ style={{
height: "56px", height: "56px",
borderRadius: 7, borderRadius: 8,
flex: 0.7, flex: 0.8,
textTransform: 'none', textTransform: 'none',
}} }}
@@ -4139,37 +4214,50 @@ const Workflows2 = (props) => {
<div style={{ <div style={{
width: "100%", width: "100%",
}}> }}>
{view === "grid" && currTab !== 2 ? ( {
<div style={{ isLoadingWorkflow ? (
display: "grid", <div style={{ textAlign: "center", marginTop: 50 }}>
gridTemplateColumns: "repeat(3, 1fr)", // Creates 3 equal columns <CircularProgress style={{ color: "#f85a3e" }} />
gap: "20px", // Adds consistent spacing between items </div>
width: "100%", ) : (
}}> view === "grid" && currTab !== 2 ? (
{filteredWorkflows.map((data, index) => { <>
// Shouldn't be a part of this list <div style={{
if (data.public === true) { display: "grid",
return null gridTemplateColumns: "repeat(3, 1fr)", // Creates 3 equal columns
} gap: "20px", // Adds consistent spacing between items
width: "100%",
}}>
if (firstLoad) {
workflowDelay += 75
} else {
return <WorkflowPaper key={index} data={data} />
}
return (
<span key={index}> {filteredWorkflows.map((data, index) => {
{/*<Zoom key={index} in={true} style={{ transitionDelay: `${workflowDelay}ms` }}>*/} // Shouldn't be a part of this list
<WorkflowPaper data={data} /> if (data.public === true) {
{/*</Zoom>*/} return null
</span> }
)
})} if (firstLoad) {
</div> workflowDelay += 75
) : ( } else {
currTab !== 2 && <WorkflowListView /> return <WorkflowPaper key={index} data={data} />
)} }
return (
<span key={index}>
{/*<Zoom key={index} in={true} style={{ transitionDelay: `${workflowDelay}ms` }}>*/}
<WorkflowPaper data={data} />
{/*</Zoom>*/}
</span>
)
})}
</div>
</>
) : (
currTab !== 2 && <WorkflowListView />
)
)
}
{ {
currTab === 2 && currTab === 2 &&
@@ -4261,7 +4349,7 @@ const Workflows2 = (props) => {
onClose={() => { }} onClose={() => { }}
PaperProps={{ PaperProps={{
style: { style: {
backgroundColor: theme.palette.surfaceColor, backgroundColor: theme.palette.surfaceColor,
color: "white", color: "white",
minWidth: "800px", minWidth: "800px",
minHeight: "320px", minHeight: "320px",
@@ -4322,8 +4410,8 @@ const Workflows2 = (props) => {
onChange={(e) => setDownloadBranch(e.target.value)} onChange={(e) => setDownloadBranch(e.target.value)}
placeholder="master" placeholder="master"
fullWidth fullWidth
/> />
</div> </div>
<span style={{ marginTop: 10 }}> <span style={{ marginTop: 10 }}>
Authentication (optional - private repos etc): Authentication (optional - private repos etc):
</span> </span>
@@ -4475,7 +4563,7 @@ const Workflows2 = (props) => {
setVideoViewOpen(true) setVideoViewOpen(true)
}}> }}>
<b>Watch 2-min introduction video</b> <b>Watch 2-min introduction video</b>
</Typography> </Typography>
</div> </div>
<div style={{ borderTop: "1px solid rgba(255,255,255,0.3)", }}> <div style={{ borderTop: "1px solid rgba(255,255,255,0.3)", }}>
{gettingStartedItems.map((item, index) => { {gettingStartedItems.map((item, index) => {