Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frontend code cleanup #426

Merged
merged 5 commits into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 86 additions & 88 deletions gui/pages/Content/Agents/ActionConsole.js
Original file line number Diff line number Diff line change
@@ -1,116 +1,114 @@
import React, { useState, useEffect } from 'react';
import styles from './Agents.module.css';
import Image from "next/image";
import Image from 'next/image';
import { updatePermissions } from '@/pages/api/DashboardService';
import { formatTime } from '@/utils/utils';

function ActionBox({ action, index, denied, reasons, handleDeny, handleSelection, setReasons }) {
const isDenied = denied[index];

return (
<div key={action.id} className={styles.history_box} style={{ background: '#272335', padding: '16px', cursor: 'default' }}>
<div style={{ display: 'flex', flexDirection: 'column' }}>
<div>Tool <b>{action.tool_name}</b> is seeking for Permissions</div>
{isDenied && (
<div style={{ marginTop: '26px' }}>
<div>Provide Feedback <span style={{ color: '#888888' }}>(Optional)</span></div>
<input style={{ marginTop: '6px' }} type="text" value={reasons[index]} placeholder="Enter your input here" className="input_medium"
onChange={(e) => {
const newReasons = [...reasons];
newReasons[index] = e.target.value;
setReasons(newReasons);
}}/>
</div>
)}
{isDenied ? (
<div style={{ display: 'inline-flex', marginTop: '16px', gap: '8px' }}>
<button onClick={() => handleDeny(index)} className="secondary_button" style={{ paddingLeft: '10px', paddingTop: '2px' }}>
<Image style={{ marginTop: '2px' }} width={12} height={12} src="/images/undo.svg" alt="check-icon" />
<span className={styles.text_12_n}>Go Back</span>
</button>
<button onClick={() => handleSelection(index, false, action.id)} className="secondary_button" style={{ paddingLeft: '10px', paddingTop: '2px', background: 'transparent', border: 'none' }}>
<span className={styles.text_12_n}>Proceed to Deny</span>
</button>
</div>
) : (
<div style={{ display: 'inline-flex', marginTop: '16px', gap: '8px' }}>
<button onClick={() => handleSelection(index, true, action.id)} className="secondary_button" style={{ paddingLeft: '10px', paddingTop: '2px' }}>
<Image style={{ marginTop: '4px' }} width={12} height={12} src="/images/check.svg" alt="check-icon" />
<span className={styles.text_12_n}>Approve</span>
</button>
<button onClick={() => handleDeny(index)} className="secondary_button" style={{ paddingLeft: '10px', paddingTop: '2px', background: 'transparent', border: 'none' }}>
<Image style={{ marginTop: '4px' }} width={16} height={16} src="/images/close.svg" alt="close-icon" />
<span className={styles.text_12_n}>Deny</span>
</button>
</div>
)}
</div>
<div style={{ display: 'flex', alignItems: 'center', paddingLeft: '0', paddingBottom: '0' }} className={styles.tab_text}>
<div>
<Image width={12} height={12} src="/images/schedule.svg" alt="schedule-icon" />
</div>
<div className={styles.history_info}>{formatTime(action.created_at)}</div>
</div>
</div>
);
}

export default function ActionConsole({ actions }) {
const [hiddenActions, setHiddenActions] = useState([]);
const [reasons, setReasons] = useState(actions.map(() => ''));
const [localActions, setLocalActions] = useState(actions);
const [denied, setDenied] = useState([]);
const [reasons, setReasons] = useState([]);
const [localActionIds, setLocalActionIds] = useState([]);

useEffect(() => {
const updatedActions = actions.filter(
(action) => !localActionIds.includes(action.id)
);

if (updatedActions.length > 0) {
setLocalActions(
localActions.map((localAction) =>
updatedActions.find(({ id }) => id === localAction.id) || localAction
)
);

const updatedDenied = updatedActions.map(() => false);
const updatedReasons = updatedActions.map(() => '');
const updatedActions = actions?.filter((action) => !localActionIds.includes(action.id));

setDenied((prev) => prev.map((value, index) => updatedDenied[index] || value));
setReasons((prev) => prev.map((value, index) => updatedReasons[index] || value));
if (updatedActions && updatedActions.length > 0) {
setLocalActionIds((prevIds) => [...prevIds, ...updatedActions.map(({ id }) => id)]);

setLocalActionIds([...localActionIds, ...updatedActions.map(({ id }) => id)]);
setDenied((prevDenied) => prevDenied.map((value, index) => updatedActions[index] ? false : value));
setReasons((prevReasons) => prevReasons.map((value, index) => updatedActions[index] ? '' : value));
}
}, [actions]);

const handleDeny = index => {
const newDeniedState = [...denied];
newDeniedState[index] = !newDeniedState[index];
setDenied(newDeniedState);
};

const formatDate = (dateString) => {
const now = new Date();
const date = new Date(dateString);
const seconds = Math.floor((now - date) / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const weeks = Math.floor(days / 7);
const months = Math.floor(days / 30);
const years = Math.floor(days / 365);

if (years > 0) return `${years} yr${years === 1 ? '' : 's'}`;
if (months > 0) return `${months} mon${months === 1 ? '' : 's'}`;
if (weeks > 0) return `${weeks} wk${weeks === 1 ? '' : 's'}`;
if (days > 0) return `${days} day${days === 1 ? '' : 's'}`;
if (hours > 0) return `${hours} hr${hours === 1 ? '' : 's'}`;
if (minutes > 0) return `${minutes} min${minutes === 1 ? '' : 's'}`;

return `${seconds} sec${seconds === 1 ? '' : 's'}`;
const handleDeny = (index) => {
setDenied((prevDenied) => {
const newDeniedState = [...prevDenied];
newDeniedState[index] = !newDeniedState[index];
return newDeniedState;
});
};

const handleSelection = (index, status, permissionId) => {
setHiddenActions([...hiddenActions, index]);
setHiddenActions((prevHiddenActions) => [...prevHiddenActions, index]);

const data = {
status: status,
user_feedback: reasons[index],
};

updatePermissions(permissionId, data).then((response) => {
console.log("voila")
});
updatePermissions(permissionId, data).then((response) => {});
};

return (
<>
{actions.some(action => action.status === "PENDING") ? (<div className={styles.detail_body} style={{ height: "auto" }}>
{actions.map((action, index) => action.status === "PENDING" && !hiddenActions.includes(index) && (
<div key={index} className={styles.history_box} style={{ background: "#272335", padding: "16px", cursor: "default" }}>
<div style={{ display: "flex", flexDirection: 'column' }}>
<div>Tool <b>{action.tool_name}</b> is seeking for Permissions</div>
{denied[index] && (
<div style={{marginTop: '26px' }}>
<div>Provide Feedback <span style={{color: '#888888'}}>(Optional)</span></div>
<input style={{marginTop: '6px'}} type="text" value={reasons[index]} onChange={(e) => {const newReasons = [...reasons];newReasons[index] = e.target.value;setReasons(newReasons);}} placeholder="Enter your input here" className="input_medium" />
</div>
)}
{denied[index] ? (
<div style={{ display: "inline-flex", marginTop: '16px',gap: '8px' }}>
<button onClick={() => handleDeny(index)} className="secondary_button"><Image width={12} height={12} src="/images/undo.svg" alt="check-icon" /><span className={styles.text_12_n}>Go Back</span></button>
<button onClick={() => handleSelection(index, false, action.id)} className="secondary_button" style={{ marginLeft: "4px", padding: "5px", background: "transparent", border: "none" }}><span className={styles.text_12_n}>Proceed to Deny</span></button>
</div>
) : (
<div style={{ display: "inline-flex", marginTop: '16px',gap: '8px' }}>
<button onClick={() => handleSelection(index, true, action.id)} className="secondary_button"><Image width={12} height={12} src="/images/check.svg" alt="check-icon" /><span className={styles.text_12_n}>Approve</span></button>
<button onClick={() => handleDeny(index)} className="secondary_button" style={{ marginLeft: "4px", padding: "5px", background: "transparent", border: "none" }}><Image width={16} height={16} src="/images/close.svg" alt="close-icon" /><div className={styles.text_12_n}>Deny</div></button>
</div>
)}
</div>
<div style={{ display: "flex", alignItems: "center", paddingLeft: "0", paddingBottom: "0" }} className={styles.tab_text}>
<div>
<Image width={12} height={12} src="/images/schedule.svg" alt="schedule-icon" />
</div>
<div className={styles.history_info}>{formatDate(action.created_at)}</div>
</div>
</div>
))}
</div>):
(
<div style={{display:'flex',flexDirection:'column',alignItems:'center',marginTop:'40px'}}>
<Image width={150} height={60} src="/images/no_permissions.svg" alt="no permissions" />
<span className={styles.feed_title} style={{marginTop: '8px'}}>No Actions to Display!</span>
</div>)}
</>
<>
{actions?.some((action) => action.status === 'PENDING') ? (
<div className={styles.detail_body} style={{ height: 'auto' }}>
{actions.map((action, index) => {
if (action.status === 'PENDING' && !hiddenActions.includes(index)) {
return (<ActionBox key={action.id} action={action} index={index} denied={denied} setReasons={setReasons}
reasons={reasons} handleDeny={handleDeny} handleSelection={handleSelection}/>);
}
return null;
})}
</div>
) : (
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginTop: '40px' }}>
<Image width={150} height={60} src="/images/no_permissions.svg" alt="no-permissions" />
<span className={styles.feed_title} style={{ marginTop: '8px' }}>No Actions to Display!</span>
</div>
)}
</>
);
}
}
12 changes: 2 additions & 10 deletions gui/pages/Content/Agents/ActivityFeed.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, {useEffect, useRef, useState} from 'react';
import styles from './Agents.module.css';
import {getExecutionFeeds} from "@/pages/api/DashboardService";
import Image from "next/image";
import {formatTime} from "@/utils/utils";
import {formatTime, loadingTextEffect} from "@/utils/utils";
import {EventBus} from "@/utils/eventBus";

export default function ActivityFeed({selectedRunId, selectedView, setFetchedData }) {
Expand All @@ -13,15 +13,7 @@ export default function ActivityFeed({selectedRunId, selectedView, setFetchedDat
const [prevFeedsLength, setPrevFeedsLength] = useState(0);

useEffect(() => {
const text = 'Thinking';
let dots = '';

const interval = setInterval(() => {
dots = dots.length < 3 ? dots + '.' : '';
setLoadingText(`${text}${dots}`);
}, 250);

return () => clearInterval(interval);
loadingTextEffect('Thinking', setLoadingText, 250);
}, []);

useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion gui/pages/Content/Agents/AgentTemplatesList.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default function AgentTemplatesList({sendAgentData, selectedProjectId, fe
</div>
<div className={styles.rowContainer} style={{maxHeight: '78vh',overflowY: 'auto',marginTop:'10px',marginLeft:'3px'}}>
{agentTemplates.length > 0 ? <div className={styles.resources} style={agentTemplates.length === 1 ? {justifyContent:'flex-start',gap:'7px'} : {}}>
{agentTemplates.map((item, index) => (
{agentTemplates.map((item) => (
<div className={styles.market_tool} key={item.id} style={{cursor: 'pointer',height:'90px'}}
onClick={() => handleTemplateClick(item)}>
<div style={{display: 'inline',overflow:'auto'}}>
Expand Down
18 changes: 11 additions & 7 deletions gui/pages/Content/Agents/AgentWorkspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {EventBus} from "@/utils/eventBus";

export default function AgentWorkspace({agentId, selectedView}) {
const [leftPanel, setLeftPanel] = useState('activity_feed')
const [rightPanel, setRightPanel] = useState('details')
const [rightPanel, setRightPanel] = useState('')
const [history, setHistory] = useState(true)
const [selectedRun, setSelectedRun] = useState(null)
const [runModal, setRunModal] = useState(false)
Expand All @@ -30,16 +30,19 @@ export default function AgentWorkspace({agentId, selectedView}) {
const addInstruction = () => {
setInstructions((prevArray) => [...prevArray, 'new instructions']);
};

const handleInstructionDelete = (index) => {
const updatedInstructions = [...instructions];
updatedInstructions.splice(index, 1);
setInstructions(updatedInstructions);
};

const handleInstructionChange = (index, newValue) => {
const updatedInstructions = [...instructions];
updatedInstructions[index] = newValue;
setInstructions(updatedInstructions);
};

const addGoal = () => {
setGoals((prevArray) => [...prevArray, 'new goal']);
};
Expand Down Expand Up @@ -138,14 +141,19 @@ export default function AgentWorkspace({agentId, selectedView}) {
fetchExecutions(agentId);
}, [agentId])

useEffect(() => {
if(agentDetails) {
setRightPanel(agentDetails.permission_type.includes('RESTRICTED') ? 'action_console' : 'details');
}
}, [agentDetails])

function fetchAgentDetails(agentId) {
getAgentDetails(agentId)
.then((response) => {
setAgentDetails(response.data);
setTools(response.data.tools);
setGoals(response.data.goal);
setInstructions(response.data.instruction);
console.log(response.data)
})
.catch((error) => {
console.error('Error fetching agent details:', error);
Expand Down Expand Up @@ -217,11 +225,7 @@ export default function AgentWorkspace({agentId, selectedView}) {
</div>
<div className={styles.detail_body}>
{leftPanel === 'activity_feed' && <div className={styles.detail_content}>
<ActivityFeed
selectedView={selectedView}
selectedRunId={selectedRun?.id || 0}
setFetchedData={setFetchedData} // Pass the setFetchedData function as a prop
/>
<ActivityFeed selectedView={selectedView} selectedRunId={selectedRun?.id || 0} setFetchedData={setFetchedData}/>
</div>}
{leftPanel === 'agent_type' && <div className={styles.detail_content}><TaskQueue selectedRunId={selectedRun?.id || 0}/></div>}
</div>
Expand Down
14 changes: 10 additions & 4 deletions gui/pages/Content/Agents/ResourceManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,16 @@ export default function ResourceManager({agentId}) {
};

const ResourceList = ({ files }) => (
<div className={styles.resources}>
{files.map((file, index) => (
<ResourceItem key={index} file={file} />
))}
<div>
{files.length <= 0 && channel === 'output' ? <div style={{display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',marginTop:'40px',width:'100%'}}>
<Image width={150} height={60} src="/images/no_permissions.svg" alt="no-permissions" />
<span className={styles.feed_title} style={{marginTop: '8px'}}>No Output files!</span>
</div> : <div className={styles.resources}>
{files.map((file, index) => (
<ResourceItem key={index} file={file} />
))}
</div>
}
</div>
);

Expand Down
9 changes: 6 additions & 3 deletions gui/pages/Content/Marketplace/Market.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ export default function Market() {

useEffect(() => {
const handleOpenTemplateDetails = (item) => {
setAgentTemplateData(item)
setItemClicked(true)
setAgentTemplateData(item);
setItemClicked(true);
};

const handleBackClick = ()=>{
setItemClicked(false)
setItemClicked(false);
}

EventBus.on('openTemplateDetails', handleOpenTemplateDetails);
EventBus.on('goToMarketplace', handleBackClick);

return () => {
EventBus.off('openTemplateDetails', handleOpenTemplateDetails);
EventBus.off('goToMarketplace', handleBackClick);
Expand Down
38 changes: 15 additions & 23 deletions gui/pages/Content/Marketplace/MarketAgent.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,30 @@ import Image from "next/image";
import styles from './Market.module.css';
import {fetchAgentTemplateList} from "@/pages/api/DashboardService";
import {EventBus} from "@/utils/eventBus";
import {loadingTextEffect} from "@/utils/utils";

export default function MarketAgent(){
const [agentTemplates, setAgentTemplates] = useState([])
const [showMarketplace, setShowMarketplace] = useState(false);
const [isLoading, setIsLoading] = useState(true)
const [loadingText, setLoadingText] = useState("Loading Templates");

useEffect(() => {
const text = 'Loading Templates';
let dots = '';

const interval = setInterval(() => {
dots = dots.length < 3 ? dots + '.' : '';
setLoadingText(`${text}${dots}`);
}, 500);
useEffect(() => {
loadingTextEffect('Loading Templates', setLoadingText, 500);

return () => clearInterval(interval);
}, []);
if(window.location.href.toLowerCase().includes('marketplace')) {
setShowMarketplace(true)
}

useEffect(() => {
if(window.location.href.toLowerCase().includes('marketplace')) {
setShowMarketplace(true)
}
fetchAgentTemplateList()
.then((response) => {
const data = response.data || [];
setAgentTemplates(data);
setIsLoading(false);
})
.catch((error) => {
console.error('Error fetching agent templates:', error);
});
fetchAgentTemplateList()
.then((response) => {
const data = response.data || [];
setAgentTemplates(data);
setIsLoading(false);
})
.catch((error) => {
console.error('Error fetching agent templates:', error);
});
}, []);

function handleTemplateClick(item) {
Expand Down
Loading