Skip to content

Commit

Permalink
feat: introduce backend for pull request notifications (DAP-4753) (#23)
Browse files Browse the repository at this point in the history
  • Loading branch information
alsakhaev committed Sep 19, 2024
1 parent e575a2a commit 1e59486
Show file tree
Hide file tree
Showing 35 changed files with 746 additions and 192 deletions.
5 changes: 5 additions & 0 deletions libs/engine/src/app/common/generate-guid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function generateGuid() {
return Array.from(crypto.getRandomValues(new Uint8Array(16)))
.map((b) => b.toString(16).padStart(2, '0'))
.join('')
}
7 changes: 4 additions & 3 deletions libs/engine/src/app/components/context-manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { Target } from '../services/target/target.entity'
import { filterAndDiscriminate } from '../common/filter-and-discriminate'
import { Document, DocumentId, DocumentMetadata } from '../services/document/document.entity'
import { ApplicationService } from '../services/application/application.service'
import { DocumentDto } from '../services/document/dtos/document.dto'

interface WidgetProps {
context: TransferableContext
Expand Down Expand Up @@ -56,7 +57,7 @@ interface WidgetProps {
ctx: TransferableContext,
dataByAccount: LinkedDataByAccountDto
) => Promise<void>
getDocument: () => Promise<Document | null>
getDocument: () => Promise<DocumentDto | null>
}

interface LayoutManagerProps {
Expand Down Expand Up @@ -387,7 +388,7 @@ const InsPointHandler: FC<{
ctx: TransferableContext,
dataByAccount: LinkedDataByAccountDto
) => Promise<void>
onGetDocumentCurry: (appInstanceId: string) => () => Promise<Document | null>
onGetDocumentCurry: (appInstanceId: string) => () => Promise<DocumentDto | null>
}> = ({
insPointName,
element,
Expand Down Expand Up @@ -560,7 +561,7 @@ const ControllerHandler: FC<{
ctx: TransferableContext,
dataByAccount: LinkedDataByAccountDto
) => Promise<void>
onGetDocumentCurry: (appInstanceId: string) => () => Promise<Document | null>
onGetDocumentCurry: (appInstanceId: string) => () => Promise<DocumentDto | null>
}> = ({
transferableContext,
controller,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,15 @@
import { useCallback, useEffect, useState } from 'react'
import { AppId } from '../../services/application/application.entity'
import { Document } from '../../services/document/document.entity'
import { useMutableWeb } from './use-mutable-web'
import { useQueryArray } from '../../hooks/use-query-array'

export const useAppDocuments = (appId: AppId) => {
const { engine } = useMutableWeb()
const [documents, setDocuments] = useState<Document[]>([])
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)

const loadDocuments = useCallback(async () => {
try {
setIsLoading(true)
const { data, isLoading, error } = useQueryArray<Document>({
query: () => engine.documentService.getDocumentsByAppId(appId),
deps: [engine, appId],
})

const documents = await engine.documentService.getDocumentsByAppId(appId)
setDocuments(documents)
} catch (err) {
console.error(err)
if (err instanceof Error) {
setError(err.message)
} else {
setError('Unknown error')
}
} finally {
setIsLoading(false)
}
}, [engine, appId])

useEffect(() => {
loadDocuments()
}, [loadDocuments])

return {
documents,
isLoading,
error,
}
return { documents: data, isLoading, error }
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,12 @@
import { useCallback, useEffect, useState } from 'react'
import { AppMetadata } from '../../services/application/application.entity'
import { Engine } from '../../../engine'
import { useQueryArray } from '../../hooks/use-query-array'

export const useApplications = (engine: Engine) => {
const [applications, setApplications] = useState<AppMetadata[]>([])
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const { data, isLoading, error } = useQueryArray<AppMetadata>({
query: () => engine.applicationService.getApplications(),
deps: [engine],
})

const loadApps = useCallback(async () => {
try {
setIsLoading(true)

const applications = await engine.applicationService.getApplications()
setApplications(applications)
} catch (err) {
console.error(err)
if (err instanceof Error) {
setError(err.message)
} else {
setError('Unknown error')
}
} finally {
setIsLoading(false)
}
}, [engine])

useEffect(() => {
loadApps()
}, [loadApps])

return {
applications,
isLoading,
error,
}
return { applications: data, isLoading, error }
}
Original file line number Diff line number Diff line change
@@ -1,45 +1,13 @@
import { useCallback, useEffect, useState } from 'react'
import { AppInstanceWithSettings } from '../../services/application/application.entity'
import { Mutation } from '../../services/mutation/mutation.entity'
import { Engine } from '../../../engine'
import { useQueryArray } from '../../hooks/use-query-array'

export const useMutationApps = (engine: Engine, mutation?: Mutation | null) => {
const [mutationApps, setMutationApps] = useState<AppInstanceWithSettings[]>([])
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const { data, setData, isLoading, error } = useQueryArray<AppInstanceWithSettings>({
query: async () => (mutation ? engine.applicationService.getAppsFromMutation(mutation) : []),
deps: [engine, mutation],
})

const loadMutationApps = useCallback(async () => {
if (!mutation) {
setMutationApps([])
return
}

try {
setIsLoading(true)

const apps = await engine.applicationService.getAppsFromMutation(mutation)

setMutationApps(apps)
} catch (err) {
console.error(err)
if (err instanceof Error) {
setError(err.message)
} else {
setError('Unknown error')
}
} finally {
setIsLoading(false)
}
}, [engine, mutation])

useEffect(() => {
loadMutationApps()
}, [loadMutationApps])

return {
mutationApps,
setMutationApps,
isLoading,
error,
}
return { mutationApps: data, setMutationApps: setData, isLoading, error }
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,13 @@
import { useCallback, useEffect, useState } from 'react'
import { AppMetadata } from '../../services/application/application.entity'
import { ParserConfig } from '../../services/parser-config/parser-config.entity'
import { Engine } from '../../../engine'
import { useQueryArray } from '../../hooks/use-query-array'

export const useMutationParsers = (engine: Engine, apps: AppMetadata[]) => {
const [parserConfigs, setParserConfigs] = useState<ParserConfig[]>([])
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const { data, isLoading, error } = useQueryArray<ParserConfig>({
query: () => engine.parserConfigService.getParserConfigsForApps(apps),
deps: [engine, apps],
})

const loadMutationParsers = useCallback(async () => {
try {
setIsLoading(true)

const parserConfigs = await engine.parserConfigService.getParserConfigsForApps(apps)

setParserConfigs(parserConfigs)
} catch (err) {
console.error(err)
if (err instanceof Error) {
setError(err.message)
} else {
setError('Unknown error')
}
} finally {
setIsLoading(false)
}
}, [engine, apps])

useEffect(() => {
loadMutationParsers()
}, [loadMutationParsers])

return {
parserConfigs,
isLoading,
error,
}
return { parserConfigs: data, isLoading, error }
}
39 changes: 6 additions & 33 deletions libs/engine/src/app/contexts/mutable-web-context/use-mutations.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,15 @@
import { useCallback, useEffect, useState } from 'react'
import { useCore } from '@mweb/react'
import { MutationWithSettings } from '../../services/mutation/mutation.entity'
import { Engine } from '../../../engine'
import { useQueryArray } from '../../hooks/use-query-array'

export const useMutations = (engine: Engine) => {
const { core } = useCore()
const [mutations, setMutations] = useState<MutationWithSettings[]>([])
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<string | null>(null)

const loadMutations = useCallback(async () => {
if (!engine) return
const { data, setData, isLoading, error } = useQueryArray<MutationWithSettings>({
query: () => engine.mutationService.getMutationsWithSettings(core.tree),
deps: [engine, core],
})

try {
setIsLoading(true)

const mutations = await engine.mutationService.getMutationsWithSettings(core.tree)
setMutations(mutations)
} catch (err) {
console.log(err)
if (err instanceof Error) {
setError(err.message)
} else {
setError('Unknown error')
}
} finally {
setIsLoading(false)
}
}, [engine, core])

useEffect(() => {
loadMutations()
}, [loadMutations])

return {
mutations,
setMutations,
isLoading,
error,
}
return { mutations: data, setMutations: setData, isLoading, error }
}
7 changes: 7 additions & 0 deletions libs/engine/src/app/contexts/notification-context/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export { NotificationContext } from './notification-context'
export { NotificationProvider } from './notification-provider'
export { useNotifications } from './use-notifications'
export { useViewNotification } from './use-view-notification'
export { useHideNotification } from './use-hide-notification'
export { useAcceptPullRequest } from './use-accept-pull-request'
export { useRejectPullRequest } from './use-reject-pull-request'
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createContext } from 'react'
import { NotificationDto } from '../../services/notification/dtos/notification.dto'

export type NotificationContextState = {
notifications: NotificationDto[]
setNotifications: React.Dispatch<React.SetStateAction<NotificationDto[]>>
isLoading: boolean
error: string | null
}

export const contextDefaultValues: NotificationContextState = {
notifications: [],
setNotifications: () => {},
isLoading: false,
error: null,
}

export const NotificationContext = createContext<NotificationContextState>(contextDefaultValues)
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { FC, ReactNode, useCallback, useEffect, useRef } from 'react'
import { NotificationContext, NotificationContextState } from './notification-context'
import { Button, Space, notification } from 'antd'
import { useViewport } from '../viewport-context'
import { useQueryArray } from '../../hooks/use-query-array'
import { NotificationDto } from '../../services/notification/dtos/notification.dto'
import { useMutableWeb } from '../mutable-web-context'

type Props = {
children?: ReactNode
recipientId: string
}

const NotificationProvider: FC<Props> = ({ children, recipientId }) => {
const { engine } = useMutableWeb()

const {
data: notifications,
setData: setNotifications,
isLoading,
error,
} = useQueryArray<NotificationDto>({
query: () => engine.notificationService.getNotificationsByRecipient(recipientId),
deps: [engine, recipientId],
})

const state: NotificationContextState = {
notifications,
setNotifications,
isLoading,
error,
}

return (
<NotificationContext.Provider value={state}>
<>{children}</>
</NotificationContext.Provider>
)
}

export { NotificationProvider }
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { usePromise } from '../../hooks/use-promise'
import { EntityId } from '../../services/base/base.entity'
import { useMutableWeb } from '../mutable-web-context'
import { useNotifications } from './use-notifications'

export const useAcceptPullRequest = (notificationId: EntityId) => {
const { engine } = useMutableWeb()
const { setNotifications } = useNotifications()

const { fetch, isLoading, error } = usePromise({
query: async () => {
const notification = await engine.mutationService.acceptPullRequest(notificationId)
setNotifications((items) =>
items.map((item) => (item.id === notification.id ? notification : item))
)
},
deps: [engine, notificationId],
})

return {
acceptPullRequest: fetch,
isLoading,
error,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { usePromise } from '../../hooks/use-promise'
import { EntityId } from '../../services/base/base.entity'
import { useMutableWeb } from '../mutable-web-context'
import { useNotifications } from './use-notifications'

export const useHideNotification = (notificationId: EntityId) => {
const { engine } = useMutableWeb()
const { setNotifications } = useNotifications()

const { fetch, isLoading, error } = usePromise({
query: async () => {
const notification = await engine.notificationService.hideNotification(notificationId)
setNotifications((items) =>
items.map((item) => (item.id === notification.id ? notification : item))
)
},
deps: [engine, notificationId],
})

return {
hideNotification: fetch,
isLoading,
error,
}
}
Loading

0 comments on commit 1e59486

Please sign in to comment.