From 06a52c818194a058ccc2532e5688ddcedaaa1e27 Mon Sep 17 00:00:00 2001 From: Antonio Sonis Date: Fri, 1 Dec 2023 19:47:12 +0100 Subject: [PATCH 1/5] feat: first commit Signed-off-by: Antonio Sonis --- package.json | 3 +- .../ConfigureEnvVarsTemplateAndPlugins.jsx | 26 +- .../configure-services/ConfigureServices.jsx | 47 +--- src/renderer/src/utils.js | 80 ++++++ test/renderer/utils.test.mjs | 236 ++++++++++++++++++ 5 files changed, 342 insertions(+), 50 deletions(-) create mode 100644 src/renderer/src/utils.js create mode 100644 test/renderer/utils.test.mjs diff --git a/package.json b/package.json index 4ee27e39..c28a0f14 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "build:mac": "npm run build && electron-builder --mac --config", "build:linux": "npm run build && electron-builder --linux --config", "test:main": "standard | snazzy && vitest ./test/main --no-threads", - "test": "npm run test:main", + "test:renderer": "standard | snazzy && vitest ./test/renderer --no-threads", + "test": "npm run test:main && npm run test:renderer", "clean": "rm -Rf ./out && rm -Rf ./dist && rm -Rf ./coverage", "release:win": "electron-builder -p always --win --config", "release:linux": "electron-builder -p always --linux --config", diff --git a/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx b/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx index 482bd4dc..c6fce8b9 100644 --- a/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx +++ b/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx @@ -11,7 +11,8 @@ import '~/components/component.animation.css' function ConfigureEnvVarsTemplateAndPlugins ({ configuredServices, - handleChangeTemplateForm + handleChangeTemplateForm, + handleChangePluginForm }) { const [serviceSelected, setServiceSelected] = useState(null) const [pluginSelected, setPluginSelected] = useState(null) @@ -27,10 +28,22 @@ function ConfigureEnvVarsTemplateAndPlugins ({ return handleChangeTemplateForm(event, serviceSelected.template, serviceSelected.name) } + function handleChangePluginEnvVars (event) { + return handleChangePluginForm(event, serviceSelected.template, serviceSelected.name, pluginSelected.name) + } + useEffect(() => { if (serviceSelected) { if (pluginSelected) { - setCurrentComponent() + setCurrentComponent( + ) } else { setCurrentComponent( {} + handleChangeTemplateForm: () => {}, + handleChangePluginForm: () => {} } export default ConfigureEnvVarsTemplateAndPlugins diff --git a/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx b/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx index 5d0a1bcb..949cf18f 100644 --- a/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx +++ b/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx @@ -10,6 +10,7 @@ import useStackablesStore from '~/useStackablesStore' import Title from '~/components/ui/Title' import '~/components/component.animation.css' import ConfigureEnvVarsTemplateAndPlugins from './ConfigureEnvVarsTemplateAndPlugins' +import { generateForm } from '../../../utils' const ConfigureServices = React.forwardRef(({ onNext, onBack }, ref) => { const globalState = useStackablesStore() @@ -19,51 +20,7 @@ const ConfigureServices = React.forwardRef(({ onNext, onBack }, ref) => { useEffect(() => { if (services.length > 0) { - const tmpServices = [] - let tmpTemplateForms = {} - let tmpTemplateValidations = {} - let tmpTemplateValidForm = {} - let tmpObj = {} - services.forEach(service => { - tmpTemplateForms = {} - tmpTemplateValidations = {} - tmpTemplateValidForm = {} - tmpObj = {} - - tmpObj.name = service.name - tmpObj.template = service.template.name - let form - let validations - let formErrors - - if (service.template.envVars.length > 0) { - form = {} - validations = {} - formErrors = {} - service.template.envVars.forEach(envVar => { - const { var: envName, configValue, type, default: envDefault, label } = envVar - form[envName] = { - label, - var: envName, - value: envDefault || '', - configValue, - type - } - validations[`${envName}Valid`] = envDefault !== '' - formErrors[envName] = '' - }) - tmpTemplateForms = { ...form } - tmpTemplateValidations = { ...validations, formErrors } - tmpTemplateValidForm = Object.keys(validations).findIndex(element => validations[element] === false) === -1 - } - tmpObj.form = { ...tmpTemplateForms } - tmpObj.validations = { ...tmpTemplateValidations } - tmpObj.validForm = tmpTemplateValidForm - tmpObj.updatedAt = new Date().toISOString() - tmpObj.plugins = [] - tmpServices.push(tmpObj) - }) - setConfiguredServices(tmpServices) + setConfiguredServices(generateForm(services)) } }, [services]) diff --git a/src/renderer/src/utils.js b/src/renderer/src/utils.js new file mode 100644 index 00000000..bea0a9a7 --- /dev/null +++ b/src/renderer/src/utils.js @@ -0,0 +1,80 @@ +export const generateForm = (services, addUpdatedAt = true) => { + const tmpServices = [] + let tmpTemplateForms = {} + let tmpTemplateValidations = {} + let tmpTemplateValidForm = {} + let tmpObj = {} + + services.forEach(service => { + tmpTemplateForms = {} + tmpTemplateValidations = {} + tmpTemplateValidForm = {} + tmpObj = {} + + tmpObj.name = service.name + tmpObj.template = service.template.name + let form + let validations + let formErrors + + if (service.template.envVars.length > 0) { + form = {} + validations = {} + formErrors = {} + service.template.envVars.forEach(envVar => { + const { var: envName, configValue, type, default: envDefault, label } = envVar + form[envName] = { + label, + var: envName, + value: envDefault || '', + configValue, + type + } + validations[`${envName}Valid`] = envDefault !== '' + formErrors[envName] = '' + }) + tmpTemplateForms = { ...form } + tmpTemplateValidations = { ...validations, formErrors } + tmpTemplateValidForm = Object.keys(validations).findIndex(element => validations[element] === false) === -1 + } + tmpObj.form = { ...tmpTemplateForms } + tmpObj.validations = { ...tmpTemplateValidations } + tmpObj.validForm = tmpTemplateValidForm + if (addUpdatedAt) { + tmpObj.updatedAt = new Date().toISOString() + } + // handling plugins + tmpObj.plugins = [] + let pluginForm + let pluginValidations + let pluginFormErrors + + (service?.plugins || []).forEach(plugin => { + pluginForm = {} + pluginValidations = {} + pluginFormErrors = {} + + if (plugin.envVars.length > 0) { + plugin.envVars.forEach(envVar => { + const { name: envName, type, default: envDefault, path } = envVar + const value = envDefault || '' + pluginForm[envName] = { + path, + value, + type + } + pluginValidations[`${envName}Valid`] = value !== '' + pluginFormErrors[envName] = '' + }) + } + tmpObj.plugins.push({ + name: plugin.name, + form: { ...pluginForm }, + validations: { ...pluginValidations, formErrors: { ...pluginFormErrors } }, + validForm: Object.keys(pluginValidations).findIndex(element => pluginValidations[element] === false) === -1 + }) + }) + tmpServices.push(tmpObj) + }) + return tmpServices +} diff --git a/test/renderer/utils.test.mjs b/test/renderer/utils.test.mjs new file mode 100644 index 00000000..98207714 --- /dev/null +++ b/test/renderer/utils.test.mjs @@ -0,0 +1,236 @@ +import { test, expect } from 'vitest' +import { generateForm } from '../../src/renderer/src/utils' + +test('return service on form without plugin', async () => { + const servicesReceived = + [ + { + template: { + orgId: 'platformatic', + orgName: 'Platformatic', + name: '@platformatic/service', + description: 'A Platformatic Service is an HTTP server based on Fastify that allows developers to build robust APIs with Node.js', + author: 'Platformatic', + homepage: 'https://platformatic.dev', + public: true, + platformaticService: true, + envVars: [ + { + var: 'PLT_SERVER_HOSTNAME', + label: 'What is the hostname?', + default: '0.0.0.0', + type: 'string', + configValue: 'hostname' + }, + { + var: 'PLT_SERVER_LOGGER_LEVEL', + label: 'What is the logger level?', + default: 'info', + type: 'string', + configValue: '' + }, + { + label: 'Which port do you want to use?', + var: 'PORT', + default: 3042, + tyoe: 'number', + configValue: 'port' + } + ] + }, + name: 'test-1', + plugins: [] + } + ] + + const expected = [{ + name: 'test-1', + template: '@platformatic/service', + form: { + PLT_SERVER_HOSTNAME: { + configValue: 'hostname', + label: 'What is the hostname?', + type: 'string', + value: '0.0.0.0', + var: 'PLT_SERVER_HOSTNAME' + }, + PLT_SERVER_LOGGER_LEVEL: { + configValue: '', + label: 'What is the logger level?', + type: 'string', + value: 'info', + var: 'PLT_SERVER_LOGGER_LEVEL' + }, + PORT: { + configValue: 'port', + label: 'Which port do you want to use?', + value: 3042, + var: 'PORT' + } + }, + validForm: true, + validations: { + PLT_SERVER_HOSTNAMEValid: true, + PLT_SERVER_LOGGER_LEVELValid: true, + PORTValid: true, + formErrors: { + PLT_SERVER_HOSTNAME: '', + PLT_SERVER_LOGGER_LEVEL: '', + PORT: '' + } + }, + plugins: [] + }] + + expect(expected).toEqual(generateForm(servicesReceived, false)) +}) + +test('return service on form with a single plugin', async () => { + const servicesReceived = + [ + { + template: { + orgId: 'platformatic', + orgName: 'Platformatic', + name: '@platformatic/service', + description: 'A Platformatic Service is an HTTP server based on Fastify that allows developers to build robust APIs with Node.js', + author: 'Platformatic', + homepage: 'https://platformatic.dev', + public: true, + platformaticService: true, + envVars: [ + { + var: 'PLT_SERVER_HOSTNAME', + label: 'What is the hostname?', + default: '0.0.0.0', + type: 'string', + configValue: 'hostname' + }, + { + var: 'PLT_SERVER_LOGGER_LEVEL', + label: 'What is the logger level?', + default: 'info', + type: 'string', + configValue: '' + }, + { + label: 'Which port do you want to use?', + var: 'PORT', + default: 3042, + tyoe: 'number', + configValue: 'port' + } + ] + }, + plugins: [ + { + name: '@fastify/accepts', + description: 'To have accepts in your request object.', + author: 'mock author', + homepage: 'https://example.com', + envVars: [ + { + name: 'PLT_COOKIE_SECRET', + path: 'secret', + type: 'string' + }, + { + name: 'PLT_COOKIE_HOOK', + path: 'hook', + type: 'string' + }, + { + name: 'PLT_COOKIE_PARSEOPTIONS_DOMAIN', + path: 'parseOptions.domain', + type: 'string' + }, + { + name: 'PLT_COOKIE_PASEOPTIONS_MAXAGE', + path: 'parseOptions.maxAge', + type: 'number' + } + ] + } + ], + name: 'lunasa-1' + } + ] + + const expected = [{ + name: 'lunasa-1', + template: '@platformatic/service', + form: { + PLT_SERVER_HOSTNAME: { + configValue: 'hostname', + label: 'What is the hostname?', + type: 'string', + value: '0.0.0.0', + var: 'PLT_SERVER_HOSTNAME' + }, + PLT_SERVER_LOGGER_LEVEL: { + configValue: '', + label: 'What is the logger level?', + type: 'string', + value: 'info', + var: 'PLT_SERVER_LOGGER_LEVEL' + }, + PORT: { + configValue: 'port', + label: 'Which port do you want to use?', + value: 3042, + var: 'PORT' + } + }, + validForm: true, + validations: { + PLT_SERVER_HOSTNAMEValid: true, + PLT_SERVER_LOGGER_LEVELValid: true, + PORTValid: true, + formErrors: { + PLT_SERVER_HOSTNAME: '', + PLT_SERVER_LOGGER_LEVEL: '', + PORT: '' + } + }, + plugins: [{ + name: '@fastify/accepts', + form: { + PLT_COOKIE_SECRET: { + value: '', + path: 'secret', + type: 'string' + }, + PLT_COOKIE_HOOK: { + value: '', + path: 'hook', + type: 'string' + }, + PLT_COOKIE_PARSEOPTIONS_DOMAIN: { + value: '', + path: 'parseOptions.domain', + type: 'string' + }, + PLT_COOKIE_PASEOPTIONS_MAXAGE: { + value: '', + path: 'parseOptions.maxAge', + type: 'number' + } + }, + validForm: false, + validations: { + PLT_COOKIE_SECRETValid: false, + PLT_COOKIE_HOOKValid: false, + PLT_COOKIE_PARSEOPTIONS_DOMAINValid: false, + PLT_COOKIE_PASEOPTIONS_MAXAGEValid: false, + formErrors: { + PLT_COOKIE_SECRET: '', + PLT_COOKIE_HOOK: '', + PLT_COOKIE_PARSEOPTIONS_DOMAIN: '', + PLT_COOKIE_PASEOPTIONS_MAXAGE: '' + } + } + }] + }] + + expect(expected).toEqual(generateForm(servicesReceived, false)) +}) From d9891ae4583a2c6863cf41a97b16229807874c2a Mon Sep 17 00:00:00 2001 From: Antonio Sonis Date: Fri, 1 Dec 2023 20:14:48 +0100 Subject: [PATCH 2/5] feat: first show of plugins Signed-off-by: Antonio Sonis --- .../components/plugins/PluginEnvVarsForm.jsx | 114 ++++++++---------- .../ConfigureEnvVarsTemplateAndPlugins.jsx | 4 +- .../templates/TemplateEnvVarsForm.jsx | 11 +- 3 files changed, 63 insertions(+), 66 deletions(-) diff --git a/src/renderer/src/components/plugins/PluginEnvVarsForm.jsx b/src/renderer/src/components/plugins/PluginEnvVarsForm.jsx index e693ab66..7fdfc307 100644 --- a/src/renderer/src/components/plugins/PluginEnvVarsForm.jsx +++ b/src/renderer/src/components/plugins/PluginEnvVarsForm.jsx @@ -1,67 +1,28 @@ 'use strict' -import React, { useState, useEffect } from 'react' +import React from 'react' import PropTypes from 'prop-types' import { BorderedBox, Forms } from '@platformatic/ui-components' import commonStyles from '~/styles/CommonStyles.module.css' import typographyStyles from '~/styles/Typography.module.css' import { OPACITY_30, TRANSPARENT, WHITE } from '@platformatic/ui-components/src/components/constants' -function PluginEnvVarsForm ({ service, plugin }) { - const [form, setForm] = useState(null) - const [validations, setValidations] = useState({ }) - // eslint-disable-next-line no-unused-vars - const [validForm, setValidForm] = useState(false) - - useEffect(() => { - if (plugin) { - const tmp = {} - const validations = {} - const formErrors = {} - - let envName - plugin.envVars.forEach(envVar => { - envName = envVar.name - tmp[envName] = '' - validations[`${envName}Valid`] = false - formErrors[envName] = '' - }) - setForm({ ...tmp }) - setValidations({ ...validations, formErrors }) - } - }, [plugin]) - - function handleChange (event) { - const value = event.target.value - validateField(event.target.name, value, setForm(form => ({ ...form, [event.target.name]: value }))) - } - - function validateField (fieldName, fieldValue, callback = () => {}) { - let tmpValid = validations[`${fieldName}Valid`] - const formErrors = { ...validations.formErrors } - switch (fieldName) { - default: - tmpValid = fieldValue.length > 0 && /^\S+$/g.test(fieldValue) - formErrors[fieldName] = fieldValue.length > 0 ? (tmpValid ? '' : 'The field is not valid, make sure you are using regular characters') : '' - break - } - const nextValidation = { ...validations, formErrors } - nextValidation[`${fieldName}Valid`] = tmpValid - setValidations(nextValidation) - validateForm(nextValidation, callback()) - } - - function validateForm (validations, callback = () => {}) { - // eslint-disable-next-line no-unused-vars - const { _formErrors, ...restValidations } = validations - const valid = Object.keys(restValidations).findIndex(element => restValidations[element] === false) === -1 - setValidForm(valid) - return callback - } +function PluginEnvVarsForm ({ + configuredServices, + onChange, + templateName, + serviceName, + pluginName +}) { + const configuredServiceFound = configuredServices.find(configuredService => configuredService.template === templateName && configuredService.name === serviceName) + const pluginFound = configuredServiceFound.plugins.find(plugin => plugin.name === pluginName) || {} function renderForm () { - return Object.keys(form).map((element) => ( + if (Object.keys(pluginFound.form).length === 0) { + return <> + } + return Object.keys(pluginFound.form).map((element) => ( env.name === element)?.path} + title={pluginFound.form[element].path} titleColor={WHITE} key={element} > @@ -69,9 +30,9 @@ function PluginEnvVarsForm ({ service, plugin }) { placeholder='Env variable example' name={element} borderColor={WHITE} - value={form[element]} - onChange={handleChange} - errorMessage={validations.formErrors[element]} + value={pluginFound.form[element].value} + onChange={onChange} + errorMessage={pluginFound.validations.formErrors[element]} backgroundTransparent inputTextClassName={`${typographyStyles.desktopBody} ${typographyStyles.textWhite}`} verticalPaddingClassName={commonStyles.noVerticalPadding} @@ -82,6 +43,13 @@ function PluginEnvVarsForm ({ service, plugin }) { )) } + function renderVariablesText () { + if (Object.keys(pluginFound.form).length === 0) { + return This plugin has no configurable variables. + } + return Variables + } + return ( -

{plugin.name} Variables

+

{pluginName} {renderVariablesText()}

- {form && renderForm()} + {pluginFound && renderForm()}
) @@ -99,11 +67,33 @@ function PluginEnvVarsForm ({ service, plugin }) { PluginEnvVarsForm.propTypes = { /** - * plugin + * configuredServices + */ + configuredServices: PropTypes.array.isRequired, + /** + * templateName + */ + templateName: PropTypes.string, + /** + * serviceName */ - plugin: PropTypes.object.isRequired + serviceName: PropTypes.string, + /** + * onChange + */ + onChange: PropTypes.func, + /** + * pluginName + */ + pluginName: PropTypes.string + } -// ConfigureEnvVarsPlugins.defaultProps = {} +PluginEnvVarsForm.defaultProps = { + templateName: '', + serviceName: '', + onChange: () => {}, + pluginName: '' +} export default PluginEnvVarsForm diff --git a/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx b/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx index c6fce8b9..e55c250f 100644 --- a/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx +++ b/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx @@ -38,11 +38,11 @@ function ConfigureEnvVarsTemplateAndPlugins ({ setCurrentComponent( ) } else { setCurrentComponent( diff --git a/src/renderer/src/components/templates/TemplateEnvVarsForm.jsx b/src/renderer/src/components/templates/TemplateEnvVarsForm.jsx index 564fedab..908e2c4a 100644 --- a/src/renderer/src/components/templates/TemplateEnvVarsForm.jsx +++ b/src/renderer/src/components/templates/TemplateEnvVarsForm.jsx @@ -16,7 +16,7 @@ function TemplateEnvVarsForm ({ function renderForm () { if (Object.keys(configuredServiceFound.form).length === 0) { - return

No variables for the template selected!

+ return <> } return Object.keys(configuredServiceFound.form).map((element) => ( This template has no configurable variables. + } + return Variables + } + return ( -

{templateName} Variables

+

{templateName} {renderVariablesText()}

{configuredServiceFound && renderForm()}
From 6f42edc3b9184541592984e551391c611f231736 Mon Sep 17 00:00:00 2001 From: Antonio Sonis Date: Fri, 1 Dec 2023 22:26:09 +0100 Subject: [PATCH 3/5] fix: updating stuff for the validations Signed-off-by: Antonio Sonis --- .../ConfigureEnvVarsTemplateAndPlugins.jsx | 2 +- .../configure-services/ConfigureServices.jsx | 63 +++++++++++++++---- src/renderer/src/utils.js | 15 +++-- test/renderer/utils.test.mjs | 4 +- 4 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx b/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx index e55c250f..464d660f 100644 --- a/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx +++ b/src/renderer/src/components/steps/configure-services/ConfigureEnvVarsTemplateAndPlugins.jsx @@ -37,7 +37,7 @@ function ConfigureEnvVarsTemplateAndPlugins ({ if (pluginSelected) { setCurrentComponent( { const fieldName = event.target.name const fieldValue = event.target.value const { form: newForm, validations: newValidations } = configuredServices.find(configuredService => configuredService.name === serviceName && configuredService.template === templateName) - + let tmpValid newForm[fieldName].value = fieldValue - - let tmpValid = newValidations[`${fieldName}Valid`] - const formErrors = { ...newValidations.formErrors } switch (fieldName) { default: tmpValid = fieldValue.length > 0 && /^\S+$/g.test(fieldValue) - formErrors[fieldName] = fieldValue.length > 0 ? (tmpValid ? '' : 'The field is not valid, make sure you are using regular characters') : '' + newValidations[`${fieldName}Valid`] = tmpValid + newValidations.formErrors[fieldName] = tmpValid ? '' : 'The field is not valid, make sure you are using regular characters' break } - const nextValidation = { ...newValidations, formErrors } - nextValidation[`${fieldName}Valid`] = tmpValid - - const newFormValid = Object.keys(nextValidation).findIndex(element => nextValidation[element] === false) === -1 - setConfiguredServices(configuredServices => { return [...configuredServices.map(configuredService => { if (configuredService.name === serviceName && configuredService.template === templateName) { const { form, validations, validForm, ...rest } = configuredService const newObject = { + ...rest, form: newForm, updatedAt: new Date().toISOString(), - validations: nextValidation, - validForm: newFormValid, - ...rest + validations: newValidations, + validForm: Object.keys(newValidations).findIndex(element => newValidations[element] === false) === -1 + } + return newObject + } else { + return configuredService + } + })] + }) + } + + function handleChangePluginForm (event, templateName, serviceName, pluginName) { + const fieldName = event.target.name + const fieldValue = event.target.value + const configuredServiceFound = configuredServices.find(configuredService => configuredService.name === serviceName && configuredService.template === templateName) + const { form: newForm, validations: newValidations } = configuredServiceFound.plugins.find(plugin => plugin.name === pluginName) + + newForm[fieldName].value = fieldValue + + const tmpValid = fieldValue.length > 0 && /^\S+$/g.test(fieldValue) + newValidations[`${fieldName}Valid`] = tmpValid + newValidations.formErrors[fieldName] = tmpValid ? '' : 'The field is not valid, make sure you are using regular characters' + + const newFormValid = Object.keys(newValidations).findIndex(element => newValidations[element] === false) === -1 + + setConfiguredServices(configuredServices => { + return [...configuredServices.map(configuredService => { + if (configuredService.name === serviceName && configuredService.template === templateName) { + const { plugins, ...rest } = configuredService + const newPlugins = plugins.map(plugin => { + if (plugin.name === pluginName) { + return { + name: pluginName, + form: newForm, + updatedAt: new Date().toISOString(), + validations: newValidations, + validForm: newFormValid + } + } else { + return plugin + } + }) + const newObject = { + ...rest, + plugins: newPlugins } return newObject } else { @@ -100,6 +136,7 @@ const ConfigureServices = React.forwardRef(({ onNext, onBack }, ref) => { diff --git a/src/renderer/src/utils.js b/src/renderer/src/utils.js index bea0a9a7..061c70dc 100644 --- a/src/renderer/src/utils.js +++ b/src/renderer/src/utils.js @@ -23,14 +23,15 @@ export const generateForm = (services, addUpdatedAt = true) => { formErrors = {} service.template.envVars.forEach(envVar => { const { var: envName, configValue, type, default: envDefault, label } = envVar + const value = envDefault || '' form[envName] = { label, var: envName, - value: envDefault || '', + value: String(value), configValue, type } - validations[`${envName}Valid`] = envDefault !== '' + validations[`${envName}Valid`] = value !== '' formErrors[envName] = '' }) tmpTemplateForms = { ...form } @@ -48,8 +49,10 @@ export const generateForm = (services, addUpdatedAt = true) => { let pluginForm let pluginValidations let pluginFormErrors + let tmpPluginObj (service?.plugins || []).forEach(plugin => { + tmpPluginObj = {} pluginForm = {} pluginValidations = {} pluginFormErrors = {} @@ -67,12 +70,16 @@ export const generateForm = (services, addUpdatedAt = true) => { pluginFormErrors[envName] = '' }) } - tmpObj.plugins.push({ + tmpPluginObj = { name: plugin.name, form: { ...pluginForm }, validations: { ...pluginValidations, formErrors: { ...pluginFormErrors } }, validForm: Object.keys(pluginValidations).findIndex(element => pluginValidations[element] === false) === -1 - }) + } + if (addUpdatedAt) { + tmpPluginObj.updatedAt = new Date().toISOString() + } + tmpObj.plugins.push(tmpPluginObj) }) tmpServices.push(tmpObj) }) diff --git a/test/renderer/utils.test.mjs b/test/renderer/utils.test.mjs index 98207714..9d4523aa 100644 --- a/test/renderer/utils.test.mjs +++ b/test/renderer/utils.test.mjs @@ -64,7 +64,7 @@ test('return service on form without plugin', async () => { PORT: { configValue: 'port', label: 'Which port do you want to use?', - value: 3042, + value: '3042', var: 'PORT' } }, @@ -177,7 +177,7 @@ test('return service on form with a single plugin', async () => { PORT: { configValue: 'port', label: 'Which port do you want to use?', - value: 3042, + value: '3042', var: 'PORT' } }, From 8ac09778815899bbd057b1827f141d96c87b25a3 Mon Sep 17 00:00:00 2001 From: Antonio Sonis Date: Fri, 1 Dec 2023 22:57:56 +0100 Subject: [PATCH 4/5] feat: fixing problem to the configureService Signed-off-by: Antonio Sonis --- .../steps/GeneratingApplication.jsx | 3 + .../configure-services/ConfigureServices.jsx | 12 +- src/renderer/src/utils.js | 17 ++ test/renderer/utils.test.mjs | 288 +++++++++++------- 4 files changed, 199 insertions(+), 121 deletions(-) diff --git a/src/renderer/src/components/steps/GeneratingApplication.jsx b/src/renderer/src/components/steps/GeneratingApplication.jsx index 9f9ac2a2..446ff336 100644 --- a/src/renderer/src/components/steps/GeneratingApplication.jsx +++ b/src/renderer/src/components/steps/GeneratingApplication.jsx @@ -28,6 +28,9 @@ const GeneratingApplication = React.forwardRef(({ onClickComplete, onRestartProc try { setCountDownStatus(RUNNING) const obj = { projectName: formData.createApplication.application, services: formData.configuredServices.services, ...formData.configureApplication } + + console.log('obj') + console.log(obj) await callCreateApp(formData.createApplication.path, obj) // setAppGeneratedSuccess(true) setCountDownStatus(SUCCESS) diff --git a/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx b/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx index 915fc82a..e9ea106e 100644 --- a/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx +++ b/src/renderer/src/components/steps/configure-services/ConfigureServices.jsx @@ -10,7 +10,7 @@ import useStackablesStore from '~/useStackablesStore' import Title from '~/components/ui/Title' import '~/components/component.animation.css' import ConfigureEnvVarsTemplateAndPlugins from './ConfigureEnvVarsTemplateAndPlugins' -import { generateForm } from '../../../utils' +import { generateForm, preapareFormForCreateApplication } from '../../../utils' const ConfigureServices = React.forwardRef(({ onNext, onBack }, ref) => { const globalState = useStackablesStore() @@ -31,16 +31,8 @@ const ConfigureServices = React.forwardRef(({ onNext, onBack }, ref) => { }, [configuredServices]) function onClickConfigureApplication () { - const services = configuredServices.map(({ name, template, form }) => ({ - name, - template, - fields: Object.keys(form).map(k => { - const { label, ...rest } = form[k] - return { ...rest } - }) - })) addFormData({ - configuredServices: { services } + configuredServices: { services: preapareFormForCreateApplication(configuredServices) } }) onNext() } diff --git a/src/renderer/src/utils.js b/src/renderer/src/utils.js index 061c70dc..f97c7e55 100644 --- a/src/renderer/src/utils.js +++ b/src/renderer/src/utils.js @@ -85,3 +85,20 @@ export const generateForm = (services, addUpdatedAt = true) => { }) return tmpServices } + +export const preapareFormForCreateApplication = configuredServices => + configuredServices.map(({ name, template, form, plugins }) => ({ + name, + template, + fields: Object.keys(form).map(k => { + const { label, ...rest } = form[k] + return { ...rest } + }), + plugins: plugins.map(plugin => ({ + name: plugin.name, + options: Object.keys(plugin.form).map(k => { + const { type, path, value } = plugin.form[k] + return { type, path, value } + }) + })) + })) diff --git a/test/renderer/utils.test.mjs b/test/renderer/utils.test.mjs index 9d4523aa..4ee75fc6 100644 --- a/test/renderer/utils.test.mjs +++ b/test/renderer/utils.test.mjs @@ -1,6 +1,120 @@ import { test, expect } from 'vitest' -import { generateForm } from '../../src/renderer/src/utils' +import { generateForm, preapareFormForCreateApplication } from '../../src/renderer/src/utils' +const expectedA = [{ + name: 'test-1', + template: '@platformatic/service', + form: { + PLT_SERVER_HOSTNAME: { + configValue: 'hostname', + label: 'What is the hostname?', + type: 'string', + value: '0.0.0.0', + var: 'PLT_SERVER_HOSTNAME' + }, + PLT_SERVER_LOGGER_LEVEL: { + configValue: '', + label: 'What is the logger level?', + type: 'string', + value: 'info', + var: 'PLT_SERVER_LOGGER_LEVEL' + }, + PORT: { + configValue: 'port', + label: 'Which port do you want to use?', + value: '3042', + var: 'PORT' + } + }, + validForm: true, + validations: { + PLT_SERVER_HOSTNAMEValid: true, + PLT_SERVER_LOGGER_LEVELValid: true, + PORTValid: true, + formErrors: { + PLT_SERVER_HOSTNAME: '', + PLT_SERVER_LOGGER_LEVEL: '', + PORT: '' + } + }, + plugins: [] +}] + +const expectedB = [{ + name: 'lunasa-1', + template: '@platformatic/service', + form: { + PLT_SERVER_HOSTNAME: { + configValue: 'hostname', + label: 'What is the hostname?', + type: 'string', + value: '0.0.0.0', + var: 'PLT_SERVER_HOSTNAME' + }, + PLT_SERVER_LOGGER_LEVEL: { + configValue: '', + label: 'What is the logger level?', + type: 'string', + value: 'info', + var: 'PLT_SERVER_LOGGER_LEVEL' + }, + PORT: { + configValue: 'port', + label: 'Which port do you want to use?', + value: '3042', + var: 'PORT' + } + }, + validForm: true, + validations: { + PLT_SERVER_HOSTNAMEValid: true, + PLT_SERVER_LOGGER_LEVELValid: true, + PORTValid: true, + formErrors: { + PLT_SERVER_HOSTNAME: '', + PLT_SERVER_LOGGER_LEVEL: '', + PORT: '' + } + }, + plugins: [{ + name: '@fastify/accepts', + form: { + PLT_COOKIE_SECRET: { + value: '', + path: 'secret', + type: 'string' + }, + PLT_COOKIE_HOOK: { + value: '', + path: 'hook', + type: 'string' + }, + PLT_COOKIE_PARSEOPTIONS_DOMAIN: { + value: '', + path: 'parseOptions.domain', + type: 'string' + }, + PLT_COOKIE_PASEOPTIONS_MAXAGE: { + value: '', + path: 'parseOptions.maxAge', + type: 'number' + } + }, + validForm: false, + validations: { + PLT_COOKIE_SECRETValid: false, + PLT_COOKIE_HOOKValid: false, + PLT_COOKIE_PARSEOPTIONS_DOMAINValid: false, + PLT_COOKIE_PASEOPTIONS_MAXAGEValid: false, + formErrors: { + PLT_COOKIE_SECRET: '', + PLT_COOKIE_HOOK: '', + PLT_COOKIE_PARSEOPTIONS_DOMAIN: '', + PLT_COOKIE_PASEOPTIONS_MAXAGE: '' + } + } + }] +}] test('return service on form without plugin', async () => { const servicesReceived = [ @@ -43,46 +157,7 @@ test('return service on form without plugin', async () => { } ] - const expected = [{ - name: 'test-1', - template: '@platformatic/service', - form: { - PLT_SERVER_HOSTNAME: { - configValue: 'hostname', - label: 'What is the hostname?', - type: 'string', - value: '0.0.0.0', - var: 'PLT_SERVER_HOSTNAME' - }, - PLT_SERVER_LOGGER_LEVEL: { - configValue: '', - label: 'What is the logger level?', - type: 'string', - value: 'info', - var: 'PLT_SERVER_LOGGER_LEVEL' - }, - PORT: { - configValue: 'port', - label: 'Which port do you want to use?', - value: '3042', - var: 'PORT' - } - }, - validForm: true, - validations: { - PLT_SERVER_HOSTNAMEValid: true, - PLT_SERVER_LOGGER_LEVELValid: true, - PORTValid: true, - formErrors: { - PLT_SERVER_HOSTNAME: '', - PLT_SERVER_LOGGER_LEVEL: '', - PORT: '' - } - }, - plugins: [] - }] - - expect(expected).toEqual(generateForm(servicesReceived, false)) + expect(expectedA).toEqual(generateForm(servicesReceived, false)) }) test('return service on form with a single plugin', async () => { @@ -156,81 +231,72 @@ test('return service on form with a single plugin', async () => { } ] + expect(expectedB).toEqual(generateForm(servicesReceived, false)) +}) + +test('prepare services without plugins', async () => { + const expected = [{ + name: 'test-1', + template: '@platformatic/service', + fields: [{ + configValue: 'hostname', + type: 'string', + value: '0.0.0.0', + var: 'PLT_SERVER_HOSTNAME' + }, { + configValue: '', + type: 'string', + value: 'info', + var: 'PLT_SERVER_LOGGER_LEVEL' + }, { + configValue: 'port', + value: '3042', + var: 'PORT' + }], + plugins: [] + }] + expect(expected).toEqual(preapareFormForCreateApplication(expectedA)) +}) + +test('prepare services with a single plugins', async () => { const expected = [{ name: 'lunasa-1', template: '@platformatic/service', - form: { - PLT_SERVER_HOSTNAME: { - configValue: 'hostname', - label: 'What is the hostname?', - type: 'string', - value: '0.0.0.0', - var: 'PLT_SERVER_HOSTNAME' - }, - PLT_SERVER_LOGGER_LEVEL: { - configValue: '', - label: 'What is the logger level?', - type: 'string', - value: 'info', - var: 'PLT_SERVER_LOGGER_LEVEL' - }, - PORT: { - configValue: 'port', - label: 'Which port do you want to use?', - value: '3042', - var: 'PORT' - } - }, - validForm: true, - validations: { - PLT_SERVER_HOSTNAMEValid: true, - PLT_SERVER_LOGGER_LEVELValid: true, - PORTValid: true, - formErrors: { - PLT_SERVER_HOSTNAME: '', - PLT_SERVER_LOGGER_LEVEL: '', - PORT: '' - } - }, + fields: [{ + configValue: 'hostname', + type: 'string', + value: '0.0.0.0', + var: 'PLT_SERVER_HOSTNAME' + }, { + configValue: '', + type: 'string', + value: 'info', + var: 'PLT_SERVER_LOGGER_LEVEL' + }, { + configValue: 'port', + value: '3042', + var: 'PORT' + }], plugins: [{ name: '@fastify/accepts', - form: { - PLT_COOKIE_SECRET: { - value: '', - path: 'secret', - type: 'string' - }, - PLT_COOKIE_HOOK: { - value: '', - path: 'hook', - type: 'string' - }, - PLT_COOKIE_PARSEOPTIONS_DOMAIN: { - value: '', - path: 'parseOptions.domain', - type: 'string' - }, - PLT_COOKIE_PASEOPTIONS_MAXAGE: { - value: '', - path: 'parseOptions.maxAge', - type: 'number' - } - }, - validForm: false, - validations: { - PLT_COOKIE_SECRETValid: false, - PLT_COOKIE_HOOKValid: false, - PLT_COOKIE_PARSEOPTIONS_DOMAINValid: false, - PLT_COOKIE_PASEOPTIONS_MAXAGEValid: false, - formErrors: { - PLT_COOKIE_SECRET: '', - PLT_COOKIE_HOOK: '', - PLT_COOKIE_PARSEOPTIONS_DOMAIN: '', - PLT_COOKIE_PASEOPTIONS_MAXAGE: '' - } - } + options: [{ + path: 'secret', + type: 'string', + value: '' + }, { + path: 'hook', + type: 'string', + value: '' + }, { + path: 'parseOptions.domain', + type: 'string', + value: '' + }, { + path: 'parseOptions.maxAge', + type: 'number', + value: '' + }] }] }] - - expect(expected).toEqual(generateForm(servicesReceived, false)) + expect(expected).toEqual(preapareFormForCreateApplication(expectedB)) }) From b1cad2d6acdd1f0b1a82a85b803b83c9e8329623 Mon Sep 17 00:00:00 2001 From: Antonio Sonis Date: Sat, 2 Dec 2023 10:09:38 +0100 Subject: [PATCH 5/5] fix: removing console.log Signed-off-by: Antonio Sonis --- src/renderer/src/components/steps/GeneratingApplication.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/renderer/src/components/steps/GeneratingApplication.jsx b/src/renderer/src/components/steps/GeneratingApplication.jsx index 446ff336..9f9ac2a2 100644 --- a/src/renderer/src/components/steps/GeneratingApplication.jsx +++ b/src/renderer/src/components/steps/GeneratingApplication.jsx @@ -28,9 +28,6 @@ const GeneratingApplication = React.forwardRef(({ onClickComplete, onRestartProc try { setCountDownStatus(RUNNING) const obj = { projectName: formData.createApplication.application, services: formData.configuredServices.services, ...formData.configureApplication } - - console.log('obj') - console.log(obj) await callCreateApp(formData.createApplication.path, obj) // setAppGeneratedSuccess(true) setCountDownStatus(SUCCESS)