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

Webhook log #1350

Draft
wants to merge 10 commits into
base: develop
Choose a base branch
from
Draft
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
15 changes: 15 additions & 0 deletions apps/sensenet/src/components/content-list/content-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,21 @@ export const ContentList = <T extends GenericContent = GenericContent>(props: Co
)
}
return null
case 'SuccessfulCalls':
return (
<ContextMenuWrapper onContextMenu={(ev) => openContext(ev, fieldOptions.rowData)}>
<VirtualDefaultCell
onTextClick={() => {
openDialog({
name: 'webhook-log',
props: { content: fieldOptions.rowData },
})
}}
cellData={fieldOptions.cellData}
textForLink=" (Click for details)"
/>
</ContextMenuWrapper>
)
default:
break
}
Expand Down
2 changes: 2 additions & 0 deletions apps/sensenet/src/components/dialogs/dialog-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
RestoreProps,
SaveQueryProps,
UploadDialogProps,
WebhookLogDialogProps,
} from '.'

export type DialogWithProps = (
Expand All @@ -39,6 +40,7 @@ export type DialogWithProps = (
| { name: 'feedback' }
| { name: 'change-password' }
| { name: 'date-range-picker'; props: DateRangePickerProps }
| { name: 'webhook-log'; props: WebhookLogDialogProps }
) & { dialogProps?: Partial<DialogProps> }

type Action = { type: 'PUSH_DIALOG'; dialog: DialogWithProps } | { type: 'POP_DIALOG' } | { type: 'CLOSE_ALL_DIALOGS' }
Expand Down
3 changes: 3 additions & 0 deletions apps/sensenet/src/components/dialogs/dialogs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const ContentPicker = lazy(() => import('./content-picker'))
const Feedback = lazy(() => import('./feedback'))
const ChangePasswordDialog = lazy(() => import('./change-password'))
const DateRangePicker = lazy(() => import('./date-range-picker'))
const WebhookLog = lazy(() => import('./webhook-log/webhook-log'))

function dialogRenderer(dialog: DialogWithProps) {
switch (dialog.name) {
Expand Down Expand Up @@ -63,6 +64,8 @@ function dialogRenderer(dialog: DialogWithProps) {
return <ChangePasswordDialog />
case 'date-range-picker':
return <DateRangePicker {...dialog.props} />
case 'webhook-log':
return <WebhookLog {...dialog.props} />
default:
return null
}
Expand Down
1 change: 1 addition & 0 deletions apps/sensenet/src/components/dialogs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './permission-editor-dialog'
export * from './reference-content-list'
export * from './restore'
export * from './save-query'
export * from './webhook-log'
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { Box, Collapse, createStyles, makeStyles, TableCell, TableRow, Theme, useTheme } from '@material-ui/core'
import { FiberManualRecord } from '@material-ui/icons'
import React, { useState } from 'react'
import { useLocalization } from '../../../hooks'
import { useDateUtils } from '../../../hooks/use-date-utils'
import { WebhookStatInput } from './types'

const useStyles = makeStyles((theme: Theme) => {
return createStyles({
row: {
'& > *': {
borderBottom: 'unset',
},
},
icon: {
height: '20px',
width: '20px',
marginRight: '16px',
},
cell: {
display: 'flex',
alignItems: 'center',
},
actionCell: {
color: theme.palette.primary.main,
cursor: 'pointer',
textDecoration: 'underline',
},
box: {
display: 'flex',
},
title: {
color: theme.palette.primary.main,
paddingRight: '16px',
},
})
})

export function CollapsibleTableRow(props: { row: WebhookStatInput }) {
const classes = useStyles()
const theme = useTheme()
const localization = useLocalization().webhookLogDialog
const dateUtils = useDateUtils()
const [open, setOpen] = useState(false)

return (
<React.Fragment>
<TableRow className={classes.row}>
<TableCell align="left">
{dateUtils.formatDate(new Date(props.row.CreationTime), 'yyyy-MM-dd HH:mm aaa')}
</TableCell>
<TableCell align="center" className={classes.cell}>
<FiberManualRecord
className={classes.icon}
style={{
color:
props.row.ResponseStatusCode < 300
? theme.palette.primary.main
: props.row.ResponseStatusCode < 400
? '#ffac33'
: '#c62828',
}}
/>
<span> HTTP {props.row.ResponseStatusCode}</span>
</TableCell>
<TableCell className={classes.actionCell} align="right" onClick={() => setOpen(!open)}>
{localization.details}
</TableCell>
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box margin={1} className={classes.box}>
<div style={{ width: '50%' }}>
<div>
<span className={classes.title}>{localization.requestTime}</span>
{dateUtils.formatDate(new Date(props.row.CreationTime), 'yyyy-MM-dd HH:mm aaa')}
</div>
<div>
<span className={classes.title}>{localization.requestLength}</span>
{props.row.RequestLength}
</div>
<div>
<span className={classes.title}>{localization.webhookId}</span>
{props.row.WebHookId}
</div>
<div>
<span className={classes.title}>{localization.eventName}</span>
{props.row.EventName}
</div>
</div>
<div style={{ width: '50%' }}>
<div>
<span className={classes.title}>{localization.duration}</span>
{props.row.Duration}
</div>
<div>
<span className={classes.title}>{localization.responseLength}</span>
{props.row.ResponseLength}
</div>
<div>
<span className={classes.title}>{localization.contentId}</span>
{props.row.ContentId}
</div>
<div>
<span className={classes.title}>{localization.errorMessage}</span>
{props.row.ErrorMessage}
</div>
</div>
</Box>
</Collapse>
</TableCell>
</TableRow>
</React.Fragment>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Table, TableBody } from '@material-ui/core'
import React from 'react'
import { CollapsibleTableRow, WebhookStatInput } from '.'

export interface CollapsibleTableProps {
webhooks: WebhookStatInput[]
}

export function CollapsibleTable({ webhooks }: CollapsibleTableProps) {
return (
<Table aria-label="collapsible table">
<TableBody>
{webhooks.map((webhookItem) => (
<CollapsibleTableRow key={webhookItem.CreationTime} row={webhookItem} />
))}
</TableBody>
</Table>
)
}
4 changes: 4 additions & 0 deletions apps/sensenet/src/components/dialogs/webhook-log/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from './collapsible-table-row'
export * from './collapsible-table'
export * from './types'
export * from './webhook-log'
12 changes: 12 additions & 0 deletions apps/sensenet/src/components/dialogs/webhook-log/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type WebhookStatInput = {
Url: string
CreationTime: string
Duration: string
RequestLength: number
ResponseLength: number
ResponseStatusCode: number
WebHookId: number | string
ContentId: number | string
EventName: string
ErrorMessage: string | null
}
67 changes: 67 additions & 0 deletions apps/sensenet/src/components/dialogs/webhook-log/webhook-log.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { WebhookSubscription } from '@sensenet/default-content-types'
import { useLogger, useRepository } from '@sensenet/hooks-react'
import { Button, DialogActions, DialogContent } from '@material-ui/core'
import React, { useEffect, useState } from 'react'
import { useGlobalStyles } from '../../../globalStyles'
import { useLocalization } from '../../../hooks'
import { useDialog } from '../dialog-provider'
import { DialogTitle } from '../dialog-title'
import { CollapsibleTable } from './collapsible-table'
import { WebhookStatInput } from '.'

export type WebhookLogDialogProps = {
content: WebhookSubscription
}

export const WebhookLogDialog: React.FunctionComponent<WebhookLogDialogProps> = (props) => {
const { closeLastDialog } = useDialog()
const globalClasses = useGlobalStyles()
const localization = useLocalization()
const logger = useLogger('WebhookLog')
const repo = useRepository()
const [data, setData] = useState<WebhookStatInput[]>([])

useEffect(() => {
const getData = async () => {
try {
const response = await repo.executeAction<any, WebhookStatInput[]>({
idOrPath: props.content.Path,
name: `GetWebHookUsageList`,
method: 'POST',
body: {},
})
console.log(response)
setData(response)
} catch (error) {
logger.error({
message: error.message,
})
}
}

getData()
}, [logger, props.content.Path, repo])

return (
<>
<DialogTitle>
<div className={globalClasses.centered}>{props.content.WebHookUrl}</div>
</DialogTitle>
<>
<DialogContent>
<CollapsibleTable webhooks={data} />
</DialogContent>
<DialogActions>
<Button
aria-label={localization.forms.cancel}
className={globalClasses.cancelButton}
onClick={closeLastDialog}>
{localization.forms.cancel}
</Button>
</DialogActions>
</>
</>
)
}

export default WebhookLogDialog
12 changes: 12 additions & 0 deletions apps/sensenet/src/localization/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,18 @@ const values = {
example: 'Example:',
defaultPayload: 'Default payload',
},
webhookLogDialog: {
log: 'Log',
details: 'Details',
requestTime: 'Request time:',
duration: 'Duration:',
requestLength: 'Request length:',
responseLength: 'Response length',
webhookId: 'Webhook id:',
contentId: 'Content id:',
eventName: 'Event name:',
errorMessage: 'Error message:',
},
editor: {},
}

Expand Down
12 changes: 12 additions & 0 deletions apps/sensenet/src/localization/hungarian.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,18 @@ const values: Localization = {
'Saját payload bármilyen valid JSON lehet. Ha az alapértelmezett payload-ot szeretné használni, hagyja üresen ezt a mezőt.',
example: 'Példa:',
},
webhookLogDialog: {
log: 'Napló',
details: 'Részletek',
requestTime: 'Kérés időpontja:',
duration: 'Válasz időtartama:',
requestLength: 'Kérés mérete:',
responseLength: 'Válasz mérete:',
webhookId: 'Webhook azonosító:',
contentId: 'Kontent azonosító:',
eventName: 'Esemény neve:',
errorMessage: 'Hibaüzenet:',
},
editor: {
common: {
cancel: 'Mégse',
Expand Down
24 changes: 24 additions & 0 deletions packages/sn-default-content-types/src/DefaultContentTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -758,3 +758,27 @@ export type Link = ListItem & {
* Content list type for grouping external links
*/
export type LinkList = ContentList

/**
* Defines an event and a 3rd party service that should be called when the event is fired.
*/
export type WebhookSubscription = GenericContent & {
/* Http method */
WebHookHttpMethod: Enums.HttpMethod[]
/* Url */
WebHookUrl: string
/* Triggers */
WebHookFilter: string
/* HTTP headers */
WebHookHeaders: string
/* Status */
Enabled: boolean

IsValid: boolean

InvalidFields: string
/* % of successful calls */
SuccessfulCalls: number
/* Custom payload */
WebHookPayload: string
}
7 changes: 7 additions & 0 deletions packages/sn-default-content-types/src/Enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,10 @@ export enum EventType {
Meeting = 'Meeting',
Demo = 'Demo',
}
export enum HttpMethod {
GET = 'GET',
POST = 'POST',
PATCH = 'PATCH',
PUT = 'PUT',
DELETE = 'DELETE',
}
Loading