From 18c9c2b745f9a07d13d22400516ecba968f8495f Mon Sep 17 00:00:00 2001 From: Akshay Sasidharan Date: Wed, 24 May 2023 13:29:02 +0530 Subject: [PATCH 1/8] fix keyring add permission issue --- docker/try-tooljet.Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/try-tooljet.Dockerfile b/docker/try-tooljet.Dockerfile index 7782071dbc..04fc64557b 100644 --- a/docker/try-tooljet.Dockerfile +++ b/docker/try-tooljet.Dockerfile @@ -1,5 +1,6 @@ FROM tooljet/tooljet-ce:latest - +# Switch to root user +USER root # copy postgrest executable COPY --from=postgrest/postgrest:v10.1.1.20221215 /bin/postgrest /bin @@ -11,7 +12,6 @@ RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor USER postgres RUN service postgresql start && \ psql -c "create role tooljet with login superuser password 'postgres';" -USER root RUN echo "[supervisord] \n" \ "nodaemon=true \n" \ @@ -33,6 +33,7 @@ RUN echo "[supervisord] \n" \ # ENV defaults ENV TOOLJET_HOST=http://localhost \ PORT=80 \ + NODE_ENV=production \ LOCKBOX_MASTER_KEY=replace_with_lockbox_master_key \ SECRET_KEY_BASE=replace_with_secret_key_base \ PG_DB=tooljet_production \ From b0de6a94a814162103f56e38398fdb222ad6f1e2 Mon Sep 17 00:00:00 2001 From: Akshay Sasidharan Date: Wed, 24 May 2023 13:45:42 +0530 Subject: [PATCH 2/8] set user --- docker/try-tooljet.Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/try-tooljet.Dockerfile b/docker/try-tooljet.Dockerfile index 04fc64557b..0e397bed0e 100644 --- a/docker/try-tooljet.Dockerfile +++ b/docker/try-tooljet.Dockerfile @@ -1,10 +1,10 @@ FROM tooljet/tooljet-ce:latest -# Switch to root user -USER root + # copy postgrest executable COPY --from=postgrest/postgrest:v10.1.1.20221215 /bin/postgrest /bin # Install Postgres +USER root RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ bullseye-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list RUN echo "deb http://deb.debian.org/debian" @@ -12,6 +12,7 @@ RUN apt update && apt -y install postgresql-13 postgresql-client-13 supervisor USER postgres RUN service postgresql start && \ psql -c "create role tooljet with login superuser password 'postgres';" +USER root RUN echo "[supervisord] \n" \ "nodaemon=true \n" \ From f85abdd01940c90eca73aa312de9403db1d0fa03 Mon Sep 17 00:00:00 2001 From: Akshay Sasidharan Date: Wed, 24 May 2023 15:55:52 +0530 Subject: [PATCH 3/8] define home dir in env for npm --- docker/try-tooljet.Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/docker/try-tooljet.Dockerfile b/docker/try-tooljet.Dockerfile index 0e397bed0e..695f17b913 100644 --- a/docker/try-tooljet.Dockerfile +++ b/docker/try-tooljet.Dockerfile @@ -51,6 +51,7 @@ ENV TOOLJET_HOST=http://localhost \ PGRST_JWT_SECRET=r9iMKoe5CRMgvJBBtp4HrqN7QiPpUToj \ ORM_LOGGING=true \ DEPLOYMENT_PLATFORM=docker:local \ + HOME=/home/appuser \ TERM=xterm # Prepare DB and start application From 88549c15c601caf7dde8d58ba2a99c15b9ba0fa1 Mon Sep 17 00:00:00 2001 From: Midhun G S Date: Wed, 24 May 2023 22:26:24 +0530 Subject: [PATCH 4/8] building fe assets synchronously (#6514) --- deploy/ec2/.env | 1 + server/src/app.module.ts | 28 +--------------------------- server/src/main.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/deploy/ec2/.env b/deploy/ec2/.env index 2e7f98451a..b1b0930c42 100644 --- a/deploy/ec2/.env +++ b/deploy/ec2/.env @@ -7,6 +7,7 @@ PG_HOST=__required__ PG_PASS=__required__ PG_DB=tooljet_prod ORM_LOGGING=true +NODE_ENV=production DEPLOYMENT_PLATFORM=ec2 # ToolJet Database diff --git a/server/src/app.module.ts b/server/src/app.module.ts index 489452226f..7d6cc10f57 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -39,8 +39,6 @@ import { GroupPermissionsModule } from './modules/group_permissions/group_permis import { TooljetDbModule } from './modules/tooljet_db/tooljet_db.module'; import { PluginsModule } from './modules/plugins/plugins.module'; import { CopilotModule } from './modules/copilot/copilot.module'; -import * as path from 'path'; -import * as fs from 'fs'; import { AppEnvironmentsModule } from './modules/app_environments/app_environments.module'; import { RequestContextModule } from './modules/request_context/request-context.module'; import { ScheduleModule } from '@nestjs/schedule'; @@ -101,31 +99,7 @@ const imports = [ CopilotModule, ]; -if (process.env.SERVE_CLIENT !== 'false') { - const filesToReplaceAssetPath = ['index.html', 'runtime.js', 'main.js']; - - for (const fileName of filesToReplaceAssetPath) { - const file = join(__dirname, '../../../', 'frontend/build', fileName); - - let newValue = process.env.SUB_PATH; - - if (process.env.SUB_PATH === undefined) { - newValue = fileName === 'index.html' ? '/' : ''; - } - - fs.readFile(file, 'utf8', function (err, data) { - if (err) { - return console.log(err); - } - const result = data - .replace(/__REPLACE_SUB_PATH__\/api/g, path.join(newValue, '/api')) - .replace(/__REPLACE_SUB_PATH__/g, newValue); - fs.writeFile(file, result, 'utf8', function (err) { - if (err) return console.log(err); - }); - }); - } - +if (process.env.SERVE_CLIENT !== 'false' && process.env.NODE_ENV === 'production') { imports.unshift( ServeStaticModule.forRoot({ // Have to remove trailing slash of SUB_PATH. diff --git a/server/src/main.ts b/server/src/main.ts index 8ba3de293f..e849928808 100644 --- a/server/src/main.ts +++ b/server/src/main.ts @@ -17,6 +17,28 @@ const fs = require('fs'); globalThis.TOOLJET_VERSION = fs.readFileSync('./.version', 'utf8').trim(); +function replaceSubpathPlaceHoldersInStaticAssets() { + const filesToReplaceAssetPath = ['index.html', 'runtime.js', 'main.js']; + + for (const fileName of filesToReplaceAssetPath) { + const file = join(__dirname, '../../../', 'frontend/build', fileName); + + let newValue = process.env.SUB_PATH; + + if (process.env.SUB_PATH === undefined) { + newValue = fileName === 'index.html' ? '/' : ''; + } + + const data = fs.readFileSync(file, { encoding: 'utf8' }); + + const result = data + .replace(/__REPLACE_SUB_PATH__\/api/g, join(newValue, '/api')) + .replace(/__REPLACE_SUB_PATH__/g, newValue); + + fs.writeFileSync(file, result, { encoding: 'utf8' }); + } +} + async function bootstrap() { const app = await NestFactory.create(AppModule, { bufferLogs: true, @@ -99,6 +121,10 @@ async function bootstrap() { const port = parseInt(process.env.PORT) || 3000; + if (process.env.SERVE_CLIENT !== 'false' && process.env.NODE_ENV === 'production') { + replaceSubpathPlaceHoldersInStaticAssets(); + } + await app.listen(port, '0.0.0.0', function () { const tooljetHost = configService.get('TOOLJET_HOST'); console.log(`Ready to use at ${tooljetHost} 🚀`); From 3282cae0e5eaa4a5fb8c0cfc74d7c54e413f8666 Mon Sep 17 00:00:00 2001 From: Midhun G S Date: Thu, 25 May 2023 11:15:46 +0530 Subject: [PATCH 5/8] bump version (#6526) --- .version | 2 +- server/.version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.version b/.version index e70b4523ae..6a6a3d8e35 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.6.0 +2.6.1 diff --git a/server/.version b/server/.version index e70b4523ae..6a6a3d8e35 100644 --- a/server/.version +++ b/server/.version @@ -1 +1 @@ -2.6.0 +2.6.1 From 1a461cd68090eded99a4134a079419db0304b1e3 Mon Sep 17 00:00:00 2001 From: Adish M <44204658+adishM98@users.noreply.github.com> Date: Thu, 25 May 2023 12:30:42 +0530 Subject: [PATCH 6/8] Changes in dockerfile for non-sudo user (#6505) --- docker/production.Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/production.Dockerfile b/docker/production.Dockerfile index b35fe66942..96f8afb7f1 100644 --- a/docker/production.Dockerfile +++ b/docker/production.Dockerfile @@ -89,7 +89,9 @@ COPY --from=builder /app/server/dist ./app/server/dist # Define non-sudo user RUN useradd --create-home appuser \ - && chown -R appuser:appuser /app + && chown -R appuser:0 /app \ + && chmod u+x /app \ + && chmod -R g=u /app USER appuser WORKDIR /app From 7aa8293d60615b151a9c39de2ef79be24b77b4ce Mon Sep 17 00:00:00 2001 From: Manish Kushare Date: Thu, 25 May 2023 17:44:08 +0530 Subject: [PATCH 7/8] Hot fixed : app is crashing upon clicking on codehinter icon in isEditable field in table column (#6510) * bug fixed app is getting crashed on clicking codehinter icon in isEditable field in table column * made the suggested changes --- .../ProgramaticallyHandleToggleSwitch.jsx | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/frontend/src/Editor/Inspector/Components/Table/ProgramaticallyHandleToggleSwitch.jsx b/frontend/src/Editor/Inspector/Components/Table/ProgramaticallyHandleToggleSwitch.jsx index 3bca48e721..852ba264f7 100644 --- a/frontend/src/Editor/Inspector/Components/Table/ProgramaticallyHandleToggleSwitch.jsx +++ b/frontend/src/Editor/Inspector/Components/Table/ProgramaticallyHandleToggleSwitch.jsx @@ -4,6 +4,7 @@ import { CodeHinter } from '../../../CodeBuilder/CodeHinter'; export const ProgramaticallyHandleToggleSwitch = ({ currentState, darkMode, + // eslint-disable-next-line no-unused-vars label, index, callbackFunction, @@ -18,28 +19,29 @@ export const ProgramaticallyHandleToggleSwitch = ({ const param = { name: property }; const definition = { value, fxActive: props.fxActive }; const initialValue = definition?.value ?? `{{false}}`; - const options = {}; return ( - callbackFunction(index, property, value)} - componentName={`widget/${component.name}::${label}`} - type={paramMeta.type} - paramName={param.name} - paramLabel={paramMeta.displayName} - fieldMeta={paramMeta} - onFxPress={(active) => { - callbackFunction(index, 'fxActive', active); - }} - fxActive={props?.fxActive ?? false} - component={component} - className="codehinter-default-input" - /> +
e.stopPropagation()}> + callbackFunction(index, property, value)} + componentName={`widget/${component?.component?.name}::${param.name}`} + type={paramMeta.type} + paramName={param.name} + paramLabel={paramMeta.displayName} + fieldMeta={paramMeta} + onFxPress={(active) => { + callbackFunction(index, 'fxActive', active); + }} + fxActive={props?.fxActive ?? false} + component={component.component} + className={options.className} + /> +
); }; From 7f281980a3b85ffe10138888fe71e7ded524f6fe Mon Sep 17 00:00:00 2001 From: Arpit Date: Fri, 26 May 2023 13:50:39 +0530 Subject: [PATCH 8/8] Hotfix - support resolving codeblocks workspace (#6551) * fixes: resolve both {{object}} and %%object%% within a single string * resolved multiple server/client/app variables together * clean up * clean up --- .../src/Editor/CodeBuilder/CodeHinter.jsx | 2 +- frontend/src/_helpers/appUtils.js | 18 ++++-- frontend/src/_helpers/utils.js | 60 ++++++++++++++++++- server/src/services/data_queries.service.ts | 32 ++++++++++ 4 files changed, 106 insertions(+), 6 deletions(-) diff --git a/frontend/src/Editor/CodeBuilder/CodeHinter.jsx b/frontend/src/Editor/CodeBuilder/CodeHinter.jsx index 55d10832ef..6c489be686 100644 --- a/frontend/src/Editor/CodeBuilder/CodeHinter.jsx +++ b/frontend/src/Editor/CodeBuilder/CodeHinter.jsx @@ -175,7 +175,7 @@ export function CodeHinter({ const getPreview = () => { if (!enablePreview) return; const customResolvables = getCustomResolvables(); - const [preview, error] = resolveReferences(currentValue, realState, null, customResolvables, true); + const [preview, error] = resolveReferences(currentValue, realState, null, customResolvables, true, true); const themeCls = darkMode ? 'bg-dark py-1' : 'bg-light py-1'; if (error) { diff --git a/frontend/src/_helpers/appUtils.js b/frontend/src/_helpers/appUtils.js index 480f30ecb1..a79187bacd 100644 --- a/frontend/src/_helpers/appUtils.js +++ b/frontend/src/_helpers/appUtils.js @@ -777,10 +777,19 @@ export function getQueryVariables(options, state) { switch (optionsType) { case 'string': { options = options.replace(/\n/g, ' '); - const dynamicVariables = getDynamicVariables(options) || []; - dynamicVariables.forEach((variable) => { - queryVariables[variable] = resolveReferences(variable, state); - }); + // check if {{var}} and %%var%% are present in the string + + if (options.includes('{{') && options.includes('%%')) { + const vars = resolveReferences(options, state); + console.log('queryVariables', { options, vars }); + queryVariables[options] = vars; + } else { + const dynamicVariables = getDynamicVariables(options) || []; + dynamicVariables.forEach((variable) => { + queryVariables[variable] = resolveReferences(variable, state); + }); + } + break; } @@ -800,6 +809,7 @@ export function getQueryVariables(options, state) { default: break; } + return queryVariables; } diff --git a/frontend/src/_helpers/utils.js b/frontend/src/_helpers/utils.js index e46edbfd66..a1797d5636 100644 --- a/frontend/src/_helpers/utils.js +++ b/frontend/src/_helpers/utils.js @@ -91,8 +91,62 @@ function resolveCode(code, state, customObjects = {}, withError = false, reserve if (withError) return [result, error]; return result; } +export function resolveString(str, state, customObjects, reservedKeyword, withError, forPreviewBox) { + let resolvedStr = str; -export function resolveReferences(object, state, defaultValue, customObjects = {}, withError = false) { + // Resolve {{object}} + const codeRegex = /(\{\{.+?\}\})/g; + const codeMatches = resolvedStr.match(codeRegex); + + if (codeMatches) { + codeMatches.forEach((codeMatch) => { + const code = codeMatch.replace('{{', '').replace('}}', ''); + + if (reservedKeyword.includes(code)) { + resolvedStr = resolvedStr.replace(codeMatch, ''); + } else { + const resolvedCode = resolveCode(code, state, customObjects, withError, reservedKeyword, true); + if (forPreviewBox) { + resolvedStr = resolvedStr.replace(codeMatch, resolvedCode[0]); + } else { + resolvedStr = resolvedStr.replace(codeMatch, resolvedCode); + } + } + }); + } + + // Resolve %%object%% + const serverRegex = /(%%.+?%%)/g; + const serverMatches = resolvedStr.match(serverRegex); + + if (serverMatches) { + serverMatches.forEach((serverMatch) => { + const code = serverMatch.replace(/%%/g, ''); + + if (code.includes('server.') && !/^server\.[A-Za-z0-9]+$/.test(code)) { + resolvedStr = resolvedStr.replace(serverMatch, ''); + } else { + const resolvedCode = resolveCode(code, state, customObjects, withError, reservedKeyword, false); + if (forPreviewBox) { + resolvedStr = resolvedStr.replace(serverMatch, resolvedCode[0]); + } else { + resolvedStr = resolvedStr.replace(serverMatch, resolvedCode); + } + } + }); + } + + return resolvedStr; +} + +export function resolveReferences( + object, + state, + defaultValue, + customObjects = {}, + withError = false, + forPreviewBox = false +) { if (object === '{{{}}}') return ''; const reservedKeyword = ['app']; //Keywords that slows down the app object = _.clone(object); @@ -100,6 +154,10 @@ export function resolveReferences(object, state, defaultValue, customObjects = { let error; switch (objectType) { case 'string': { + if (object.includes('{{') && object.includes('}}') && object.includes('%%') && object.includes('%%')) { + object = resolveString(object, state, customObjects, reservedKeyword, withError, forPreviewBox); + } + if (object.startsWith('{{') && object.endsWith('}}')) { const code = object.replace('{{', '').replace('}}', ''); diff --git a/server/src/services/data_queries.service.ts b/server/src/services/data_queries.service.ts index 14dbb6c585..d68936b0f4 100644 --- a/server/src/services/data_queries.service.ts +++ b/server/src/services/data_queries.service.ts @@ -409,6 +409,38 @@ export class DataQueriesService { return object; } else if (typeof object === 'string') { object = object.replace(/\n/g, ' '); + + //if object has {{}} and %%%% then resolve %% in a single string + if (object.includes('{{') && object.includes('}}') && object.includes('%%') && object.includes('%%')) { + let resolvedvar = options[object]; + + if (object.includes(`server.`)) { + // find all server variables in the string + const serverVariables = object.match(/server.(.*?)%%/g); + + serverVariables?.map((variable) => { + return variable + .match(/server.(.*?)%%/g)[0] + .replace('%%', '') + .replace('server.', ''); + }); + + const resolvedOrgVar = []; + + for (const variable of serverVariables) { + const resolvedVariable = await this.resolveVariable(variable, organization_id); + resolvedOrgVar.push(resolvedVariable); + } + + //replace the HiddenEnvironmentVariable with the resolved value + for (let i = 0; i < serverVariables.length; i++) { + resolvedvar = resolvedvar.replace('HiddenEnvironmentVariable', resolvedOrgVar[i]); + } + } + + return resolvedvar; + } + if (object.startsWith('{{') && object.endsWith('}}') && (object.match(/{{/g) || []).length === 1) { object = options[object]; return object;