From 29cd35c1644ac325f43d60a561b85c891b4f0f10 Mon Sep 17 00:00:00 2001 From: Rafael Araujo Lehmkuhl Date: Wed, 6 Nov 2024 13:58:32 -0300 Subject: [PATCH] cockpit-actions: Add Vanilla JavaScript actions With this, the user can create vanilla JavaScript methods that can be called from anywhere in the application. This basically allows one to extend Cockpit capabilities to anything. --- .../configuration/JavascriptActionConfig.vue | 304 ++++++++++++++++++ src/libs/actions/free-javascript.ts | 98 ++++++ src/views/ConfigurationActionsView.vue | 2 + 3 files changed, 404 insertions(+) create mode 100644 src/components/configuration/JavascriptActionConfig.vue create mode 100644 src/libs/actions/free-javascript.ts diff --git a/src/components/configuration/JavascriptActionConfig.vue b/src/components/configuration/JavascriptActionConfig.vue new file mode 100644 index 000000000..1306fd999 --- /dev/null +++ b/src/components/configuration/JavascriptActionConfig.vue @@ -0,0 +1,304 @@ + + + + + diff --git a/src/libs/actions/free-javascript.ts b/src/libs/actions/free-javascript.ts new file mode 100644 index 000000000..72b18b58b --- /dev/null +++ b/src/libs/actions/free-javascript.ts @@ -0,0 +1,98 @@ +import { + CockpitAction, + CockpitActionsFunction, + deleteAction, + registerActionCallback, + registerNewAction, +} from '../joystick/protocols/cockpit-actions' + +const javascriptActionIdPrefix = 'javascript-action' + +export type JavascriptActionConfig = { + /** + * The name of the action + */ + name: string + /** + * The JavaScript code to execute + */ + code: string +} + +let registeredJavascriptActionConfigs: Record = {} + +export const registerJavascriptActionConfig = (action: JavascriptActionConfig): void => { + const id = `${javascriptActionIdPrefix} (${action.name})` + registeredJavascriptActionConfigs[id] = action + saveJavascriptActionConfigs() + updateCockpitActions() +} + +export const getJavascriptActionConfig = (id: string): JavascriptActionConfig | undefined => { + return registeredJavascriptActionConfigs[id] +} + +export const getAllJavascriptActionConfigs = (): Record => { + return registeredJavascriptActionConfigs +} + +export const deleteJavascriptActionConfig = (id: string): void => { + delete registeredJavascriptActionConfigs[id] + saveJavascriptActionConfigs() + updateCockpitActions() +} + +export const updateCockpitActions = (): void => { + Object.entries(registeredJavascriptActionConfigs).forEach(([id]) => { + if (id.includes(javascriptActionIdPrefix)) { + deleteAction(id as CockpitActionsFunction) + } + }) + + const javascriptActions = getAllJavascriptActionConfigs() + for (const [id, action] of Object.entries(javascriptActions)) { + try { + const cockpitAction = new CockpitAction(id as CockpitActionsFunction, action.name) + registerNewAction(cockpitAction) + registerActionCallback(cockpitAction, getJavascriptActionCallback(id)) + } catch (error) { + console.error(`Error registering action ${id}: ${error}`) + } + } +} + +export const loadJavascriptActionConfigs = (): void => { + const savedActions = localStorage.getItem('cockpit-javascript-actions') + if (savedActions) { + registeredJavascriptActionConfigs = JSON.parse(savedActions) + } +} + +export const saveJavascriptActionConfigs = (): void => { + localStorage.setItem('cockpit-javascript-actions', JSON.stringify(registeredJavascriptActionConfigs)) +} + +export type JavascriptActionCallback = () => void + +export const executeActionCode = (code: string): void => { + try { + // Execute the code + new Function(code)() + } catch (error) { + console.error(`Error executing JavaScript action:`, error) + } +} + +export const getJavascriptActionCallback = (id: string): JavascriptActionCallback => { + const action = getJavascriptActionConfig(id) + if (!action) { + throw new Error(`Action with id ${id} not found.`) + } + + return () => { + executeActionCode(action.code) + } +} + +loadJavascriptActionConfigs() +updateCockpitActions() diff --git a/src/views/ConfigurationActionsView.vue b/src/views/ConfigurationActionsView.vue index 4100b5e1f..0b80c61a8 100644 --- a/src/views/ConfigurationActionsView.vue +++ b/src/views/ConfigurationActionsView.vue @@ -106,6 +106,7 @@ + @@ -315,6 +316,7 @@