Skip to content

Commit

Permalink
add alert api & plugin
Browse files Browse the repository at this point in the history
misc fixes
  • Loading branch information
Armaldio committed Aug 16, 2024
1 parent 15855d0 commit ae90dfa
Show file tree
Hide file tree
Showing 20 changed files with 304 additions and 32 deletions.
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ exec "${process.execPath}" "$@"
}
})
} else */ if (node.type === 'action') {
return handleActionExecute(node.origin.nodeId, node.origin.pluginId, params, {
return handleActionExecute(node.origin.nodeId, node.origin.pluginId, params, mainWindow, {
send: (data) => {
logger.info('send', data)
}
Expand Down
109 changes: 109 additions & 0 deletions src/main/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { BrowserWindow } from 'electron'
import { klona } from 'klona'
import { toRaw } from 'vue'

import { RendererPluginDefinition } from '@cyn/plugin-core'
import type { Tagged } from 'type-fest'

type Event<TYPE extends string, DATA> = { type: TYPE; data: DATA }
type EndEvent<DATA> = { type: 'end'; data: DATA }


export type IpcDefinition = {
'dialog:alert': [
// input
{ message: string; buttons?: { title: string; value: string }[] },
EndEvent<{ answer: string }>
]
}

export type RendererChannels = keyof IpcDefinition
export type RendererData<KEY extends RendererChannels> = IpcDefinition[KEY][0]
export type RendererEvents<KEY extends RendererChannels> = IpcDefinition[KEY][1]
export type RendererEnd<KEY extends RendererChannels> = Extract<IpcDefinition[KEY][1], { type: 'end' }>['data']

export type RendererMessage = {
// the channel to communicate
requestId: RequestId
data: any
}
export type RequestId = Tagged<string, 'request-id'>

// type Output = End<'fs:openFolder'>

export type HandleListenerSendFn<KEY extends RendererChannels> = (events: RendererEvents<KEY>) => void

export type HandleListener<KEY extends RendererChannels> = (
event: Electron.IpcMainInvokeEvent,
data: { value: RendererData<KEY>; send: HandleListenerSendFn<KEY> }
) => Promise<void>

export type ListenerMain<KEY extends RendererChannels> = (
event: Electron.IpcMainEvent,
data: RendererEvents<KEY>
) => Promise<void>

export const usePluginAPI = (browserWindow: BrowserWindow) => {
/**
* Send an order
*/
const send = <KEY extends RendererChannels>(channel: KEY, args?: RendererData<KEY>) =>
// browserWindow.webContents.send(channel, args)
browserWindow.webContents.send(channel, args)

const on = <KEY extends RendererChannels>(
channel: KEY | string,
listener: (event: Electron.IpcMainEvent, data: RendererEvents<KEY>) => void
) => {
const ipcMain = browserWindow.webContents.ipc.on(channel, listener)

const cancel = () => ipcMain.removeListener(channel, listener)

return cancel
}

/**
* Send an order and wait for it's execution
*/
const execute = async <KEY extends RendererChannels>(
channel: KEY,
data?: RendererData<KEY>,
listener?: ListenerMain<KEY>
) => {
const { nanoid } = await import('nanoid')
const newId = nanoid() as RequestId
// eslint-disable-next-line no-async-promise-executor
return new Promise<RendererEnd<KEY>>(async (resolve) => {
const message: RendererMessage = {
requestId: newId,
data: toRaw(klona(data))
}

const cancel = on(newId, async (event, data) => {
// console.log('receiving event', event, data)
if (data.type === 'end') {
cancel()
return resolve(data.data)
} else {
await listener?.(event, data)
}
})

// send the message
try {
browserWindow.webContents.send(channel, message)
} catch (e) {
console.error(e)
console.error(channel, message)
}
})
}

return {
send,
on,
execute
}
}

export type UseMainAPI = ReturnType<typeof usePluginAPI>
11 changes: 10 additions & 1 deletion src/main/handler-func.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { join } from 'node:path'
import { HandleListenerSendFn } from './handlers'
import { assetsPath, unpackPath } from './paths'
import { logger } from '@@/logger'
import { BrowserWindow } from 'electron'
import { usePluginAPI } from './api'

const checkParams = (definitionParams: InputsDefinition, elementParams: any) => {
// get a list of all required params
Expand Down Expand Up @@ -111,6 +113,7 @@ export const handleActionExecute = async (
nodeId: string,
pluginId: string,
params: any,
mainWindow: BrowserWindow | undefined,
{ send }: { send: HandleListenerSendFn<'action:execute'> }
): Promise<End<'action:execute'>> => {
const { plugins } = usePlugins()
Expand Down Expand Up @@ -144,6 +147,11 @@ export const handleActionExecute = async (
const _unpackPath = await unpackPath()

const outputs: Record<string | number | symbol, unknown> = {}

console.log('mainWindow', mainWindow)

const api = usePluginAPI(mainWindow)

await node.runner({
inputs: resolvedInputs,
log: (...args) => {
Expand All @@ -162,7 +170,8 @@ export const handleActionExecute = async (
paths: {
assets: _assetsPath,
unpack: _unpackPath
}
},
api,
})
return {
outputs
Expand Down
6 changes: 4 additions & 2 deletions src/main/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,12 @@ export const registerIPCHandlers = () => {
})
})

handle('action:execute', async (_, { send, value }) => {
handle('action:execute', async (event, { send, value }) => {
const { nodeId, params, pluginId } = value

const result = await handleActionExecute(nodeId, pluginId, params, {
const mainWindow = BrowserWindow.fromWebContents(event.sender)

const result = await handleActionExecute(nodeId, pluginId, params, mainWindow, {
send,
})

Expand Down
8 changes: 4 additions & 4 deletions src/renderer/components/nodes/EditorNodeAction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ import { createQuickJs } from '@renderer/utils/quickjs'
import DOMPurify from 'dompurify'
import { makeResolvedParams } from '@renderer/utils/evaluator'
import { ValidationError } from '@renderer/models/error'
import { fmt } from '@renderer/utils/fmt'
import AddNodeButton from '../AddNodeButton.vue'
const props = defineProps({
Expand Down Expand Up @@ -145,10 +144,11 @@ const resolvedParams = computedAsync(
}
)
const vm = await createQuickJs()
const subtitle = computedAsync(
async () => {
const displayString = nodeDefinition.value?.displayString ?? ''
const vm = await createQuickJs()
const result = await vm.run(displayString, {
params: resolvedParams.value,
steps: steps.value
Expand Down Expand Up @@ -176,7 +176,6 @@ const showSidebar = ref(false)
display: flex;
flex-direction: column;
align-items: center;
background-color: white;
}
.node-action {
Expand All @@ -186,6 +185,7 @@ const showSidebar = ref(false)
border-radius: 4px;
width: fit-content;
background-color: white;
box-shadow:
0 0 #0000,
0 0 #0000,
Expand All @@ -197,7 +197,7 @@ const showSidebar = ref(false)
}
&.error {
background-color: rgba(255, 0, 0, 0.1);
background-color: #ffcccc;
}
}
Expand Down
51 changes: 44 additions & 7 deletions src/renderer/components/nodes/EditorNodeEvent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,18 @@

<script setup lang="ts">
import { useEditor } from '@renderer/store/editor'
import { BlockEvent } from '@@/model'
import { BlockEvent, Steps } from '@@/model'
import { storeToRefs } from 'pinia'
import { PropType, computed, ref, toRefs } from 'vue'
import { computedAsync } from '@vueuse/core'
import { makeResolvedParams } from '@renderer/utils/evaluator'
import ParamEditor from './ParamEditor.vue'
import { Event } from '@cyn/plugin-core'
import DOMPurify from 'dompurify'
import PluginIcon from './PluginIcon.vue'
import { ValidationError } from '@renderer/models/error'
import AddNodeButton from '../AddNodeButton.vue'
import { createQuickJs } from '@renderer/utils/quickjs'
const props = defineProps({
value: {
Expand All @@ -78,14 +81,18 @@ const props = defineProps({
required: true
// default: () => []
},
steps: {
type: Object as PropType<Steps>,
required: true
},
errors: {
type: Object as PropType<ValidationError[]>,
required: false,
default: () => []
}
})
const { value } = toRefs(props)
const { value, steps } = toRefs(props)
const editor = useEditor()
const { getNodeDefinition, getPluginDefinition, setTriggerValue, addNode, removeTrigger } = editor
Expand Down Expand Up @@ -116,13 +123,43 @@ const onValueChanged = (newValue: unknown, paramKey: string) => {
})
}
const resolvedParams = computedAsync(
async () => {
return makeResolvedParams(
{
params: value.value.params,
steps: steps.value,
context: {},
variables: []
},
(item) => {
// console.log('item', item)
// const cleanOutput = DOMPurify.sanitize(item)
// console.log('cleanOutput', cleanOutput)
// return `<div class=\"param\">${cleanOutput}</div>`
return item
}
)
},
{},
{
onError: (error) => {
console.error('error', error)
}
}
)
const subtitle = computedAsync(
async () => {
// const result = await engine.parseAndRender(nodeDefinition.value?.displayString ?? '', {
// params: value.value.params
// })
// return result
return 'TODO'
const displayString = nodeDefinition.value?.displayString ?? ''
const vm = await createQuickJs()
const result = await vm.run(displayString, {
params: resolvedParams.value,
steps: steps.value
})
const clean = DOMPurify.sanitize(result)
return clean
},
'Loading...',
{
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/nodes/ParamEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ const $codeEditorText = ref<HTMLDivElement>()
const $floating = ref<HTMLDivElement>()
const $arrow = ref<HTMLElement>()
const isValueSimpleBoolean = (str: string) => {
const isValueSimpleBoolean = (str: string | unknown) => {
return str === 'true' || str === 'false'
}
Expand Down
13 changes: 9 additions & 4 deletions src/renderer/composables/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ export type Listener<KEY extends Channels> = (
data: Events<KEY>
) => Promise<void>

export const useAPI = () => {
export const useAPI = (pipe: {
send: (channel: string, ...args: any[]) => void;
on: any
} = window.electron.ipcRenderer) => {
/**
* Send an order
*/
const send = <KEY extends Channels>(channel: KEY, args?: Data<KEY>) =>
window.electron.ipcRenderer.send(channel, args)
pipe.send(channel, args)

const on = <KEY extends Channels>(
channel: KEY | string,
listener: (event: Electron.IpcRendererEvent, data: Events<KEY>) => void
) => {
// console.log('listening for', channel)
return window.electron.ipcRenderer.on(channel, listener)
return pipe.on(channel, listener)
}

/**
Expand Down Expand Up @@ -54,7 +57,7 @@ export const useAPI = () => {
})

try {
window.electron.ipcRenderer.send(channel, message)
pipe.send(channel, message)
} catch (e) {
console.error(e)
console.error(channel, message)
Expand All @@ -68,3 +71,5 @@ export const useAPI = () => {
execute
}
}

export type UseAPI = ReturnType<typeof useAPI>
1 change: 0 additions & 1 deletion src/renderer/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ if (window.isPackaged && process.env.TEST !== 'true') {
dsn: "https://[email protected]/4507621723144192",
debug: true,
integrations: [
// @ts-expect-error
breadcrumbsIntegration({
console: false
})
Expand Down
Loading

0 comments on commit ae90dfa

Please sign in to comment.