Skip to content

Commit

Permalink
cockpit-actions: Add support for custom http-request actions
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaellehmkuhl committed Oct 14, 2024
1 parent a5a03db commit a6fa73d
Show file tree
Hide file tree
Showing 3 changed files with 841 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ import { useAppInterfaceStore } from './stores/appInterface'
import { useMainVehicleStore } from './stores/mainVehicle'
import { useWidgetManagerStore } from './stores/widgetManager'
import { ConfigComponent } from './types/general'
import ConfigurationActionsView from './views/ConfigurationActionsView.vue'
import ConfigurationAlertsView from './views/ConfigurationAlertsView.vue'
import ConfigurationDevelopmentView from './views/ConfigurationDevelopmentView.vue'
import ConfigurationGeneralView from './views/ConfigurationGeneralView.vue'
Expand Down Expand Up @@ -410,6 +411,11 @@ const configMenu = [
title: 'Mission',
component: markRaw(ConfigurationMissionView) as ConfigComponent,
},
{
icon: 'mdi-run-fast',
title: 'Actions',
component: markRaw(ConfigurationActionsView) as ConfigComponent,
},
]
watch(
Expand Down
160 changes: 160 additions & 0 deletions src/libs/actions/http-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import {
availableCockpitActions,
CockpitAction,
CockpitActionsFunction,
deleteAction,
registerActionCallback,
registerNewAction,
} from '../joystick/protocols/cockpit-actions'
import { getCockpitActionVariableData } from './data-lake'

const httpRequestActionIdPrefix = 'http-request-action'

/**
* The types of HTTP methods that can be used.
*/
export enum HttpRequestMethod {
GET = 'GET',
POST = 'POST',
PUT = 'PUT',
DELETE = 'DELETE',
PATCH = 'PATCH',
}
export const availableHttpRequestMethods: HttpRequestMethod[] = Object.values(HttpRequestMethod)

export type HttpRequestActionConfig = {
/**
* The name of the action.
*/
name: string
/**
* The URL to send the request to.
*/
url: string
/**
* The HTTP method to use.
*/
method: HttpRequestMethod
/**
* The headers to send with the request.
*/
headers: Record<string, string>
/**
* The URL parameters to send with the request.
*/
urlParams: Record<string, string>
/**
* The body of the request.
*/
body: string
}

let registeredHttpRequestActionConfigs: Record<string, HttpRequestActionConfig> = {}

export const registerHttpRequestActionConfig = (action: HttpRequestActionConfig): void => {
const id = `${httpRequestActionIdPrefix} (${action.name})`
registeredHttpRequestActionConfigs[id] = action
saveHttpRequestActionConfigs()
updateCockpitActions()
}

export const getHttpRequestActionConfig = (id: string): HttpRequestActionConfig | undefined => {
return registeredHttpRequestActionConfigs[id]
}

export const getAllHttpRequestActionConfigs = (): Record<string, HttpRequestActionConfig> => {
return registeredHttpRequestActionConfigs
}

export const deleteHttpRequestActionConfig = (id: string): void => {
delete registeredHttpRequestActionConfigs[id]
saveHttpRequestActionConfigs()
updateCockpitActions()
}

export const updateHttpRequestActionConfig = (id: string, updatedAction: HttpRequestActionConfig): void => {
registeredHttpRequestActionConfigs[id] = updatedAction
saveHttpRequestActionConfigs()
updateCockpitActions()
}

export const updateCockpitActions = (): void => {
Object.entries(availableCockpitActions).forEach(([id]) => {
if (id.includes(httpRequestActionIdPrefix)) {
deleteAction(id as CockpitActionsFunction)
}
})

const httpResquestActions = getAllHttpRequestActionConfigs()
for (const [id, action] of Object.entries(httpResquestActions)) {
try {
const cockpitAction = new CockpitAction(id as CockpitActionsFunction, action.name)
registerNewAction(cockpitAction)
registerActionCallback(cockpitAction, getHttpRequestActionCallback(id))
} catch (error) {
console.error(`Error registering action ${id}: ${error}`)
}
}
}

export const loadHttpRequestActionConfigs = (): void => {
const savedActions = localStorage.getItem('cockpit-http-request-actions')
if (savedActions) {
registeredHttpRequestActionConfigs = JSON.parse(savedActions)
}
}

export const saveHttpRequestActionConfigs = (): void => {
localStorage.setItem('cockpit-http-request-actions', JSON.stringify(registeredHttpRequestActionConfigs))
}

export type HttpRequestActionCallback = () => void

export const getHttpRequestActionCallback = (id: string): HttpRequestActionCallback => {
const action = getHttpRequestActionConfig(id)
if (!action) {
throw new Error(`Action with id ${id} not found.`)
}

let parsedBody = action.body
const parsedUrlParams = action.urlParams

const cockpitInputsInBody = action.body.match(/{{\s*([^{}\s]+)\s*}}/g)
if (cockpitInputsInBody) {
for (const input of cockpitInputsInBody) {
const parsedInput = input.replace('{{', '').replace('}}', '').trim()
const inputData = getCockpitActionVariableData(parsedInput)
if (inputData) {
parsedBody = parsedBody.replace(input, inputData.toString())
}
}
}

const cockpitInputsInUrlParams = Object.entries(action.urlParams).filter(
([, value]) => typeof value === 'string' && value.startsWith('{{') && value.endsWith('}}')
)
if (cockpitInputsInUrlParams) {
for (const [key, value] of cockpitInputsInUrlParams) {
const parsedInput = value.replace('{{', '').replace('}}', '').trim()
const inputData = getCockpitActionVariableData(parsedInput)
if (inputData) {
parsedUrlParams[key] = inputData.toString()
}
}
}

const url = new URL(action.url)

url.search = new URLSearchParams(parsedUrlParams).toString()

return () => {
fetch(url, {
method: action.method,
headers: action.headers,
body: action.method === HttpRequestMethod.GET ? undefined : parsedBody,
})
}
}

loadHttpRequestActionConfigs()
updateCockpitActions()
Loading

0 comments on commit a6fa73d

Please sign in to comment.