Skip to content

Commit 3bbce9c

Browse files
authored
Merge pull request #799 from factly/feat/797/add-webhooks-action-list
Feat/797/add-webhooks-logs-list
2 parents d9d26d6 + 8785c9c commit 3bbce9c

12 files changed

Lines changed: 245 additions & 26 deletions

File tree

server/service/core/action/webhook/logs.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import (
44
"encoding/json"
55
"fmt"
66
"net/http"
7+
"strconv"
78

89
"github.com/factly/dega-server/service/core/model"
910
"github.com/factly/x/errorx"
1011
"github.com/factly/x/loggerx"
1112
"github.com/factly/x/middlewarex"
1213
"github.com/factly/x/renderx"
1314
"github.com/factly/x/requestx"
15+
"github.com/go-chi/chi"
1416
"github.com/spf13/viper"
1517
)
1618

@@ -32,6 +34,15 @@ type logPaging struct {
3234
// @Success 200 {object} paging
3335
// @Router /core/webhooks/logs [get]
3436
func logs(w http.ResponseWriter, r *http.Request) {
37+
webhookID := chi.URLParam(r, "webhook_id")
38+
wID, err := strconv.Atoi(webhookID)
39+
40+
if err != nil {
41+
loggerx.Error(err)
42+
errorx.Render(w, errorx.Parser(errorx.InvalidID()))
43+
return
44+
}
45+
3546
uID, err := middlewarex.GetUser(r.Context())
3647
if err != nil {
3748
loggerx.Error(err)
@@ -46,7 +57,7 @@ func logs(w http.ResponseWriter, r *http.Request) {
4657
return
4758
}
4859

49-
hukzURL := viper.GetString("hukz_url") + "/webhooks/logs?tag=app:dega&tag=space:" + fmt.Sprint(sID) + "&limit=" + r.URL.Query().Get("limit") + "&page=" + r.URL.Query().Get("page")
60+
hukzURL := viper.GetString("hukz_url") + "/webhooks/space/" + fmt.Sprint(sID) + "/webhook/" + fmt.Sprint(wID) + "/logs?tag=app:dega&tag=space:" + fmt.Sprint(sID) + "&limit=" + r.URL.Query().Get("limit") + "&page=" + r.URL.Query().Get("page")
5061

5162
resp, err := requestx.Request("GET", hukzURL, nil, map[string]string{
5263
"X-User": fmt.Sprint(uID),

server/service/core/action/webhook/route.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ func Router() chi.Router {
2222

2323
r.With(util.CheckKetoPolicy(entity, "get")).Get("/", list)
2424
r.With(util.CheckKetoPolicy(entity, "create")).Post("/", create)
25-
r.With(util.CheckKetoPolicy(entity, "get")).Get("/logs", logs)
2625
r.Route("/{webhook_id}", func(r chi.Router) {
26+
r.With(util.CheckKetoPolicy(entity, "get")).Get("/logs", logs)
2727
r.With(util.CheckKetoPolicy(entity, "get")).Get("/", details)
2828
r.With(util.CheckKetoPolicy(entity, "update")).Put("/", update)
2929
r.With(util.CheckKetoPolicy(entity, "delete")).Delete("/", delete)

studio/src/actions/webhooklogs.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import axios from 'axios';
2+
import {
3+
ADD_WEBHOOKLOGS,
4+
ADD_WEBHOOKLOGS_REQUEST,
5+
SET_WEBHOOKLOGS_LOADING,
6+
RESET_WEBHOOKLOGS,
7+
} from '../constants/webhooklogs';
8+
import { addErrorNotification, addSuccessNotification } from './notifications';
9+
import { addEvents } from './events';
10+
import getError from '../utils/getError';
11+
import { WEBHOOKS_API } from '../constants/webhooks';
12+
13+
export const getWebhooklogs = (id, query) => {
14+
return (dispatch) => {
15+
dispatch(loadingWebhookLogs());
16+
return axios
17+
.get(WEBHOOKS_API + '/' + id + '/logs', {
18+
params: query,
19+
})
20+
.then((response) => {
21+
dispatch(addWebhooklogList(response.data.nodes));
22+
dispatch(
23+
addWebhookRequest({
24+
data: response.data.nodes.map((item) => item.id),
25+
query: query,
26+
total: response.data.total,
27+
}),
28+
);
29+
})
30+
.catch((error) => {
31+
dispatch(addErrorNotification(getError(error)));
32+
})
33+
.finally(() => dispatch(stopWebhookLogsLoading()));
34+
};
35+
};
36+
37+
export const loadingWebhookLogs = () => ({
38+
type: SET_WEBHOOKLOGS_LOADING,
39+
payload: true,
40+
});
41+
export const stopWebhookLogsLoading = () => ({
42+
type: SET_WEBHOOKLOGS_LOADING,
43+
payload: false,
44+
});
45+
export const addWebhooklogList = (data) => ({
46+
type: ADD_WEBHOOKLOGS,
47+
payload: data,
48+
});
49+
export const addWebhookRequest = (data) => ({
50+
type: ADD_WEBHOOKLOGS_REQUEST,
51+
payload: data,
52+
});
53+
export const resetWebhooks = () => ({
54+
type: RESET_WEBHOOKLOGS,
55+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
//Actions
2+
export const ADD_WEBHOOKLOG = 'ADD_WEBHOOKLOG';
3+
export const ADD_WEBHOOKLOGS = 'ADD_WEBHOOKLOGS';
4+
export const ADD_WEBHOOKLOGS_REQUEST = 'ADD_WEBHOOKLOGS_REQUEST';
5+
export const RESET_WEBHOOKLOGS = 'RESET_WEBHOOKLOGS';
6+
export const SET_WEBHOOKLOGS_LOADING = 'SET_WEBHOOKLOGS_LOADING';

studio/src/pages/webhooks/EditWebhook.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { useDispatch, useSelector } from 'react-redux';
44
import { updateWebhook, getWebhook } from '../../actions/webhooks';
55
import { useHistory } from 'react-router-dom';
66
import { useParams } from 'react-router-dom';
7-
import { Skeleton } from 'antd';
7+
import { Skeleton , Row , Col } from 'antd';
88
import RecordNotFound from '../../components/ErrorsAndImage/RecordNotFound';
99
import { Helmet } from 'react-helmet';
10+
import Webhooklogs from './webhooklogs';
1011

1112
function EditWebhook() {
1213
const history = useHistory();
@@ -37,7 +38,10 @@ function EditWebhook() {
3738
return (
3839
<>
3940
<Helmet title={'Edit Webhook'} />
40-
<WebhookEditForm data={webhook} onCreate={onUpdate} />
41+
<Row>
42+
<Col span={16}><WebhookEditForm data={webhook} onCreate={onUpdate} /></Col>
43+
<Col span={8}><Webhooklogs WebhookId={webhook.id}/></Col>
44+
</Row>
4145
</>
4246
);
4347
}

studio/src/pages/webhooks/components/WebhookForm.js

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,30 @@ import { Button, Form, Input, Space, Switch, Checkbox, Row, Col } from 'antd';
33
import { useDispatch, useSelector } from 'react-redux';
44
import { getEvents } from '../../../actions/events';
55
import deepEqual from 'deep-equal';
6+
import { getEventName } from '../../../utils/event';
67

7-
const layout = {
8-
labelCol: {
9-
span: 8,
10-
},
11-
wrapperCol: {
12-
span: 10,
13-
},
14-
};
158
const tailLayout = {
169
wrapperCol: {
1710
offset: 10,
1811
span: 14,
1912
},
2013
};
2114

22-
const buttonLayout = {
23-
wrapperCol: {
24-
offset: 2,
25-
span: 10,
26-
},
27-
};
2815
const WebhookForm = ({ onCreate, data = {} }) => {
16+
const layout = {
17+
labelCol: {
18+
span: data?.id ? 5 : 8,
19+
},
20+
wrapperCol: {
21+
span: 10,
22+
},
23+
};
24+
const buttonLayout = {
25+
wrapperCol: {
26+
offset: data?.id ? 1 : 2,
27+
span: 10,
28+
},
29+
};
2930
const [form] = Form.useForm();
3031
const [valueChange, setValueChange] = React.useState(false);
3132
const dispatch = useDispatch();
@@ -62,13 +63,6 @@ const WebhookForm = ({ onCreate, data = {} }) => {
6263
const fetchEvents = () => {
6364
dispatch(getEvents(filters));
6465
};
65-
const getEventName = (eventLabel) => {
66-
var labelArr = eventLabel.split('.');
67-
for (var i = 0; i < labelArr.length; i++) {
68-
labelArr[i] = labelArr[i][0].toUpperCase() + labelArr[i].slice(1);
69-
}
70-
return labelArr.join(' ');
71-
};
7266
if (events) {
7367
return (
7468
<Form
@@ -110,7 +104,7 @@ const WebhookForm = ({ onCreate, data = {} }) => {
110104
{...buttonLayout}
111105
style={{
112106
display: 'flex',
113-
justifyContent: 'center',
107+
justifyContent: 'space-around',
114108
alignItems: 'center',
115109
}}
116110
>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import { Table } from 'antd';
3+
import { getEventName } from '../../../../utils/event';
4+
import { getDateAndTimeFromString } from '../../../../utils/date';
5+
function WebhookLogsList({data, filters, setFilters}) {
6+
const columns = [
7+
{
8+
title: 'Event',
9+
dataIndex: 'event',
10+
key: 'event',
11+
render: (_, record) => getEventName(record.event)
12+
},
13+
{
14+
title: 'Time',
15+
dataIndex: 'created_at',
16+
key: 'created_at',
17+
render: (_, record) => getDateAndTimeFromString(record.created_at)
18+
}
19+
];
20+
21+
return (
22+
<Table
23+
bordered
24+
columns={columns}
25+
dataSource={data.webhooklogs}
26+
loading={data.loading}
27+
rowKey={'id'}
28+
pagination={{
29+
total: data.total,
30+
current: filters.page,
31+
pageSize: filters.limit,
32+
onChange: (pageNumber, pageSize) => setFilters({ page: pageNumber, limit: pageSize }),
33+
pageSizeOptions: ['10', '15', '20'],
34+
}}
35+
/>
36+
);
37+
}
38+
39+
export default WebhookLogsList;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import { Space } from 'antd';
3+
import { useDispatch, useSelector } from 'react-redux';
4+
import deepEqual from 'deep-equal';
5+
import { getWebhooklogs } from '../../../actions/webhooklogs';
6+
import WebhookLogsList from './components/WebhookLogsList';
7+
8+
function Webhooklogs({WebhookId}) {
9+
const spaces = useSelector(({ spaces }) => spaces);
10+
const dispatch = useDispatch();
11+
const [filters, setFilters] = React.useState({
12+
page: 1,
13+
limit: 20,
14+
});
15+
const { webhooklogs, total, loading } = useSelector((state) => {
16+
const node = state.webhooklogs.req.find((item) => {
17+
return deepEqual(item.query, filters);
18+
});
19+
if (node)
20+
return {
21+
webhooklogs: node.data.map((element) => state.webhooklogs.details[element]),
22+
total: node.total,
23+
loading: state.webhooks.loading,
24+
};
25+
return { webhooklogs: [], total: 0, loading: state.webhooklogs.loading };
26+
});
27+
React.useEffect(() => {
28+
fetchWebhooklogs();
29+
// eslint-disable-next-line react-hooks/exhaustive-deps
30+
}, [filters]);
31+
32+
const fetchWebhooklogs = () => {
33+
dispatch(getWebhooklogs(WebhookId,filters));
34+
};
35+
36+
return (
37+
<Space direction="vertical">
38+
<WebhookLogsList
39+
data={{ webhooklogs, total, loading }}
40+
filters={filters}
41+
setFilters={setFilters}
42+
fetchWebhooks={fetchWebhooklogs}
43+
/>
44+
</Space>
45+
);
46+
}
47+
48+
export default Webhooklogs;

studio/src/reducers/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import profile from './profileReducer';
3434
import search from './searchReducer';
3535
import sachFactChecks from './sachFactChecksReducer';
3636
import roles from './rolesReducer';
37+
import webhooklogs from './webhooklogsReducer';
3738

3839
const appReducer = combineReducers({
3940
admin,
@@ -66,6 +67,7 @@ const appReducer = combineReducers({
6667
sidebar,
6768
events,
6869
webhooks,
70+
webhooklogs,
6971
profile,
7072
search,
7173
sachFactChecks,
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {
2+
ADD_WEBHOOKLOG,
3+
ADD_WEBHOOKLOGS,
4+
ADD_WEBHOOKLOGS_REQUEST,
5+
SET_WEBHOOKLOGS_LOADING,
6+
RESET_WEBHOOKLOGS,
7+
} from '../constants/webhooklogs';
8+
import deepEqual from 'deep-equal';
9+
10+
const initialState = {
11+
req: [],
12+
details: {},
13+
loading: true,
14+
};
15+
16+
export default function webhooklogsReducer(state = initialState, action = {}) {
17+
switch (action.type) {
18+
case RESET_WEBHOOKLOGS:
19+
return {
20+
...state,
21+
req: [],
22+
details: {},
23+
loading: true,
24+
};
25+
case SET_WEBHOOKLOGS_LOADING:
26+
return {
27+
...state,
28+
loading: action.payload,
29+
};
30+
case ADD_WEBHOOKLOGS_REQUEST:
31+
return {
32+
...state,
33+
req: state.req
34+
.filter((value) => !deepEqual(value.query, action.payload.query))
35+
.concat(action.payload),
36+
};
37+
case ADD_WEBHOOKLOGS:
38+
if (action.payload.length === 0) {
39+
return state;
40+
}
41+
return {
42+
...state,
43+
details: {
44+
...state.details,
45+
...action?.payload?.reduce((obj, item) => Object.assign(obj, { [item.id]: item }), {}),
46+
},
47+
};
48+
default:
49+
return state;
50+
}
51+
}

0 commit comments

Comments
 (0)