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

Added filters in the webhooks #1140

Merged
merged 37 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4e62d61
fix
rounak610 Aug 11, 2023
97cbc07
webhooks frontend + api calls complete almost
namansleeps2 Aug 21, 2023
ee53fd0
Merge remote-tracking branch 'origin/dev' into dev
rounak610 Aug 22, 2023
1b1a12e
webhooks compplete frontend
namansleeps2 Aug 23, 2023
8655121
Merge branch 'dev' of https://github.com/TransformerOptimus/SuperAGI …
rounak610 Aug 28, 2023
9f52ebd
Merge branch 'dev' of https://github.com/TransformerOptimus/SuperAGI …
rounak610 Aug 28, 2023
3d180f3
added filters in the webhooks
rounak610 Aug 28, 2023
898d40f
fix
rounak610 Aug 28, 2023
5d63f8f
added filters in the webhooks
rounak610 Aug 28, 2023
dc84435
Merge branch 'dev' of github.com:TransformerOptimus/SuperAGI into web…
namansleeps2 Aug 29, 2023
8eb134e
added filters in the webhooks
rounak610 Aug 29, 2023
7d90ea0
Merge branch 'webhook_dev' into webhooks_new
rounak610 Aug 29, 2023
68bf955
adding of filters table and edit functionality is on the way
namansleeps2 Aug 29, 2023
d00124d
Merge remote-tracking branch 'origin/webhooks_new' into webhooks_new
namansleeps2 Aug 29, 2023
4ef811b
added filters in webhooks
rounak610 Aug 30, 2023
41180c8
Merge branch 'webhooks_new' of https://github.com/TransformerOptimus/…
rounak610 Aug 30, 2023
df718e5
added filters in webhooks
rounak610 Aug 30, 2023
1ca7e3e
minor changes
namansleeps2 Aug 30, 2023
6c0dca4
Merge branch 'webhooks_new' of github.com:TransformerOptimus/SuperAGI…
namansleeps2 Aug 30, 2023
0e15c68
webhooks complete
namansleeps2 Aug 30, 2023
ab37d67
minor changes for PR
namansleeps2 Aug 30, 2023
5c14715
minor changes for PR
namansleeps2 Aug 30, 2023
1dd9611
added filters in webhooks
rounak610 Aug 30, 2023
a382161
Merge branch 'webhooks_new' of https://github.com/TransformerOptimus/…
rounak610 Aug 30, 2023
576f31d
resolving conflicts
namansleeps2 Aug 30, 2023
5f50b66
added filters in webhooks
rounak610 Aug 30, 2023
7a29b3e
Merge branch 'webhooks_new' of https://github.com/TransformerOptimus/…
rounak610 Aug 30, 2023
eb48d88
resolving conflicts
namansleeps2 Aug 30, 2023
0ed457f
Merge remote-tracking branch 'origin/webhooks_new' into webhooks_new
namansleeps2 Aug 30, 2023
f0659e5
added filters in the webhooks
rounak610 Aug 31, 2023
7e15b6e
bug fix of prev PR
namansleeps2 Aug 31, 2023
d069216
Merge remote-tracking branch 'origin/webhooks_new' into webhooks_new
namansleeps2 Aug 31, 2023
d741fa8
added filters in webhooks
rounak610 Aug 31, 2023
62dd221
Merge branch 'webhooks_new' of https://github.com/TransformerOptimus/…
rounak610 Aug 31, 2023
1f5e6d5
added filters in the webhooks
rounak610 Aug 31, 2023
a56dbe6
added filters in the webhooks
rounak610 Aug 31, 2023
7a08bd6
Update conftest.py
Fluder-Paradyne Aug 31, 2023
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
21 changes: 21 additions & 0 deletions gui/pages/Content/Marketplace/Market.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -529,3 +529,24 @@
.settings_tab_img{
margin-top: -1px;
}

.checkboxGroup {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
height: 15vh;
}

.checkboxLabel {
display: flex;
align-items: center;
width: 15vw;
cursor:pointer
}

.checkboxText {
font-weight: 400;
font-size: 12px;
color: #FFF;
margin-left:5px;
}
2 changes: 1 addition & 1 deletion gui/pages/Content/Toolkits/Metrics.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export default function Metrics({toolName, knowledgeName}) {
<table className="w_100 margin_0 padding_0">
<thead>
<tr className="border_top_none text_align_left border_bottom_none">
<th className="table_header w_15">Longest Timestamp</th>
<th className="table_header w_15">Log Timestamp</th>
<th className="table_header w_15">Agent Name</th>
<th className="table_header w_40">Run Name</th>
<th className="table_header w_15">Model</th>
Expand Down
6 changes: 6 additions & 0 deletions gui/pages/Dashboard/Settings/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Image from "next/image";
import Model from "@/pages/Dashboard/Settings/Model";
import Database from "@/pages/Dashboard/Settings/Database";
import ApiKeys from "@/pages/Dashboard/Settings/ApiKeys";
import Webhooks from "@/pages/Dashboard/Settings/Webhooks";

export default function Settings({organisationId, sendDatabaseData}) {
const [activeTab, setActiveTab] = useState('model');
Expand Down Expand Up @@ -38,12 +39,17 @@ export default function Settings({organisationId, sendDatabaseData}) {
<Image width={14} height={14} src="/images/key_white.svg" alt="api-key-icon"/>
<span>API Keys</span>
</button>
<button onClick={() => switchTab('webhooks')} className={activeTab === 'webhooks' ? 'tab_button_selected' : 'tab_button'}>
<Image className={styles.settings_tab_img} width={14} height={14} src="/images/webhook_icon.svg"
alt="database-icon"/>&nbsp;Webhooks
</button>
</div>
</div>
<div>
{activeTab === 'model' && <Model organisationId={organisationId}/>}
{activeTab === 'database' && <Database sendDatabaseData={sendDatabaseData} organisationId={organisationId}/>}
{activeTab === 'apikeys' && <ApiKeys />}
{activeTab === 'webhooks' && <Webhooks />}
</div>
</div>
</div>
Expand Down
148 changes: 148 additions & 0 deletions gui/pages/Dashboard/Settings/Webhooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import React, {useState, useEffect} from 'react';
import {ToastContainer, toast} from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import agentStyles from "@/pages/Content/Agents/Agents.module.css";
import {
editWebhook,
getWebhook, saveWebhook,
} from "@/pages/api/DashboardService";
import {loadingTextEffect, removeTab} from "@/utils/utils";
import styles from "@/pages/Content/Marketplace/Market.module.css";
export default function Webhooks() {
const [webhookUrl, setWebhookUrl] = useState('');
const [webhookId, setWebhookId] = useState(-1);
const [isLoading, setIsLoading] = useState(true)
const [existingWebhook, setExistingWebhook] = useState(false)
const [isEdtiting, setIsEdtiting] = useState(false)
const [loadingText, setLoadingText] = useState("Loading Webhooks");
const [selectedCheckboxes, setSelectedCheckboxes] = useState([]);
const checkboxes = [
{ label: 'Agent is running', value: 'RUNNING' },
{ label: 'Agent run is paused', value: 'PAUSED' },
{ label: 'Agent run is completed', value: 'COMPLETED' },
{ label: 'Agent is terminated ', value: 'TERMINATED' },
{ label: 'Agent run max iteration reached', value: 'MAX ITERATION REACHED' },
];


useEffect(() => {
loadingTextEffect('Loading Webhooks', setLoadingText, 500);
fetchWebhooks();
}, []);

const handleWebhookChange = (event) => {
setWebhookUrl(event.target.value);
};

const handleSaveWebhook = () => {
if(!webhookUrl || webhookUrl.trim() === ""){
toast.error("Enter valid webhook", {autoClose: 1800});
return;
}
if(isEdtiting){
editWebhook(webhookId, { url: webhookUrl, filters: {status: selectedCheckboxes}})
.then((response) => {
setIsEdtiting(false)
fetchWebhooks()
toast.success("Webhook deleted successfully", {autoClose: 1800});
})
.catch((error) => {
console.error('Error fetching webhook', error);
});
return;
}
saveWebhook({name : "Webhook 1", url: webhookUrl, headers: {}, filters: {status: selectedCheckboxes}})
.then((response) => {
setExistingWebhook(true)
setWebhookId(response.data.id)
toast.success("Webhook created successfully", {autoClose: 1800});
})
.catch((error) => {
toast.error("Unable to create webhook", {autoClose: 1800});
console.error('Error saving webhook', error);
});
}

const fetchWebhooks = () => {
getWebhook()
.then((response) => {
setIsLoading(false)
if(response.data){
setWebhookUrl(response.data.url)
setExistingWebhook(true)
setWebhookId(response.data.id)
setSelectedCheckboxes(response.data.filters.status)
}
else{
setWebhookUrl('')
setExistingWebhook(false)
setWebhookId(-1)
}
})
.catch((error) => {
console.error('Error fetching webhook', error);
});
}

const toggleCheckbox = (value) => {
if (selectedCheckboxes.includes(value)) {
setSelectedCheckboxes(selectedCheckboxes.filter((item) => item !== value));
} else {
setSelectedCheckboxes([...selectedCheckboxes, value]);
}
};

return (<>
<div className="row">
<div className="col-3"></div>
<div className="col-6 col-6-scrollable">
{!isLoading ? <div>
<div className="title_wrapper mb_15">
<div className={styles.page_title}>Webhooks</div>
{existingWebhook &&
<button className="primary_button" onClick={() => {setExistingWebhook(false);setIsEdtiting(true)} } >
Edit
</button>}
</div>

<div>
<label className={agentStyles.form_label}>Destination URL</label>
<input disabled={existingWebhook ? true : false} className="input_medium" placeholder="Enter your destination url" type="text" value={webhookUrl}
onChange={handleWebhookChange}/>
<br />
<label className={agentStyles.form_label}>Events to include</label>
<div className={styles.checkboxGroup} >
{checkboxes.map((checkbox) => (
<label key={checkbox.value} className={styles.checkboxLabel}>
<input
disabled={existingWebhook ? true : false}
className="checkbox"
type="checkbox"
value={checkbox.value}
checked={selectedCheckboxes.includes(checkbox.value)}
onChange={() => toggleCheckbox(checkbox.value)}
/>
<span className={styles.checkboxText}>&nbsp;{checkbox.label}</span>
</label>
))}
</div>
</div>

{!existingWebhook && <div className="justify_end display_flex_container mt_15">
<button onClick={() => removeTab(-3, "Settings", "Settings", 0)} className="secondary_button mr_10">
Cancel
</button>
<button className="primary_button" onClick={handleSaveWebhook}>
{isEdtiting ? "Update" : "Create"}
</button>
</div>}

</div> : <div className="loading_container">
<div className="signInInfo loading_text">{loadingText}</div>
</div>}
</div>
<div className="col-3"></div>
</div>
<ToastContainer/>
</>)
}
12 changes: 12 additions & 0 deletions gui/pages/api/DashboardService.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,18 @@ export const deleteApiKey = (apiId) => {
return api.delete(`/api-keys/${apiId}`);
};

export const saveWebhook = (webhook) => {
return api.post(`/webhook/add`, webhook);
};

export const getWebhook = () => {
return api.get(`/webhook/get`);
};

export const editWebhook = (webhook_id, webook_data) => {
return api.post(`/webhook/edit/${webhook_id}`, webook_data);
};

export const publishToMarketplace = (executionId) => {
return api.post(`/agent_templates/publish_template/agent_execution_id/${executionId}`);
};
Expand Down
3 changes: 3 additions & 0 deletions gui/public/images/webhook_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions migrations/versions/40affbf3022b_add_filter_colume_in_webhooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""add filter colume in webhooks

Revision ID: 40affbf3022b
Revises: 5d5f801f28e7
Create Date: 2023-08-28 12:30:35.171176

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '40affbf3022b'
down_revision = '5d5f801f28e7'
branch_labels = None
depends_on = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('webhooks', sa.Column('filters', sa.JSON(), nullable=True))
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('webhooks', 'filters')
# ### end Alembic commands ###
65 changes: 60 additions & 5 deletions superagi/controllers/webhook.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from datetime import datetime

from fastapi import APIRouter
from typing import Optional
from fastapi import APIRouter, HTTPException
from fastapi import Depends
from fastapi_jwt_auth import AuthJWT
from fastapi_sqlalchemy import db
Expand All @@ -17,6 +17,7 @@
name: str
url: str
headers: dict
filters: dict

class Config:
orm_mode = True
Expand All @@ -31,12 +32,21 @@
is_deleted: bool
created_at: datetime
updated_at: datetime
filters: dict

class Config:
orm_mode = True

class WebHookEdit(BaseModel):
url: str
filters: dict

class Config:
orm_mode = True


# CRUD Operations

# CRUD Operations`
@router.post("/add", response_model=WebHookOut, status_code=201)
def create_webhook(webhook: WebHookIn, Authorize: AuthJWT = Depends(check_auth),
organisation=Depends(get_user_organisation)):
Expand All @@ -52,9 +62,54 @@
HTTPException (Status Code=404): If the associated project is not found.
"""
db_webhook = Webhooks(name=webhook.name, url=webhook.url, headers=webhook.headers, org_id=organisation.id,
is_deleted=False)
is_deleted=False, filters=webhook.filters)
db.session.add(db_webhook)
db.session.commit()
db.session.flush()

return db_webhook

@router.get("/get", response_model=Optional[WebHookOut])
def get_all_webhooks(
Authorize: AuthJWT = Depends(check_auth),
organisation=Depends(get_user_organisation),
):
"""
Retrieves a single webhook for the authenticated user's organisation.

Returns:
JSONResponse: A JSON response containing the retrieved webhook.

Raises:
"""
webhook = db.session.query(Webhooks).filter(Webhooks.org_id == organisation.id, Webhooks.is_deleted == False).first()
return webhook

Check warning on line 85 in superagi/controllers/webhook.py

View check run for this annotation

Codecov / codecov/patch

superagi/controllers/webhook.py#L84-L85

Added lines #L84 - L85 were not covered by tests

@router.post("/edit/{webhook_id}", response_model=WebHookOut)
def edit_webhook(
updated_webhook: WebHookEdit,
webhook_id: int,
Authorize: AuthJWT = Depends(check_auth),
organisation=Depends(get_user_organisation),
):
"""
Soft-deletes a webhook by setting the value of is_deleted to True.

Args:
webhook_id (int): The ID of the webhook to delete.

Returns:
WebHookOut: The deleted webhook.

Raises:
HTTPException (Status Code=404): If the webhook is not found.
"""
webhook = db.session.query(Webhooks).filter(Webhooks.org_id == organisation.id, Webhooks.id == webhook_id, Webhooks.is_deleted == False).first()

Check warning on line 106 in superagi/controllers/webhook.py

View check run for this annotation

Codecov / codecov/patch

superagi/controllers/webhook.py#L106

Added line #L106 was not covered by tests
if webhook is None:
raise HTTPException(status_code=404, detail="Webhook not found")

Check warning on line 108 in superagi/controllers/webhook.py

View check run for this annotation

Codecov / codecov/patch

superagi/controllers/webhook.py#L108

Added line #L108 was not covered by tests

webhook.url = updated_webhook.url
webhook.filters = updated_webhook.filters

Check warning on line 111 in superagi/controllers/webhook.py

View check run for this annotation

Codecov / codecov/patch

superagi/controllers/webhook.py#L110-L111

Added lines #L110 - L111 were not covered by tests

db.session.commit()

Check warning on line 113 in superagi/controllers/webhook.py

View check run for this annotation

Codecov / codecov/patch

superagi/controllers/webhook.py#L113

Added line #L113 was not covered by tests

return webhook

Check warning on line 115 in superagi/controllers/webhook.py

View check run for this annotation

Codecov / codecov/patch

superagi/controllers/webhook.py#L115

Added line #L115 was not covered by tests
Loading