From 5c037048934714425c1b645a8b1785d745d6f65e Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Wed, 26 Mar 2025 04:41:00 +0530 Subject: [PATCH 1/8] Server side query support added --- frontend/ee | 2 +- .../CodeEditor/MultiLineCodeEditor.jsx | 34 ++++++++++++++++- .../src/AppBuilder/CodeEditor/PreviewBox.jsx | 9 ++++- .../CodeEditor/SingleLineCodeEditor.jsx | 38 +++++++++++++++++-- frontend/src/AppBuilder/CodeEditor/utils.js | 11 ++++++ frontend/webpack.config.js | 2 +- server/ee | 2 +- .../data-queries/interfaces/IUtilService.ts | 3 +- .../src/modules/data-queries/util.service.ts | 31 +++++++++++---- .../data-sources/interfaces/IUtilService.ts | 2 +- server/src/modules/data-sources/module.ts | 2 + .../src/modules/data-sources/util.service.ts | 22 +++++++---- .../modules/licensing/configs/LicenseBase.ts | 12 ++++++ .../modules/licensing/constants/PlanTerms.ts | 1 + .../src/modules/licensing/constants/index.ts | 1 + server/src/modules/licensing/helper.ts | 3 ++ .../src/modules/licensing/interfaces/terms.ts | 1 + .../organization-constants/constants/index.ts | 1 + .../src/modules/organization-users/module.ts | 4 +- server/src/modules/users/module.ts | 26 ++++++++++++- 20 files changed, 176 insertions(+), 31 deletions(-) diff --git a/frontend/ee b/frontend/ee index d93ee7e131..715a830c7a 160000 --- a/frontend/ee +++ b/frontend/ee @@ -1 +1 @@ -Subproject commit d93ee7e1318f044ef2327671b8b257648071453d +Subproject commit 715a830c7a8d75efc7f77106292d9e4499005b69 diff --git a/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx b/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx index f95baaa328..b447df7efd 100644 --- a/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx +++ b/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx @@ -7,6 +7,7 @@ import { keymap } from '@codemirror/view'; import { completionKeymap, acceptCompletion, autocompletion, completionStatus } from '@codemirror/autocomplete'; import { python } from '@codemirror/lang-python'; import { sql } from '@codemirror/lang-sql'; +import _ from 'lodash'; import { sass, sassCompletionSource } from '@codemirror/lang-sass'; import { okaidia } from '@uiw/codemirror-theme-okaidia'; import { githubLight } from '@uiw/codemirror-theme-github'; @@ -21,6 +22,7 @@ import useStore from '@/AppBuilder/_stores/store'; import { shallow } from 'zustand/shallow'; import { search, searchKeymap, searchPanelOpen } from '@codemirror/search'; import { handleSearchPanel, SearchBtn } from './SearchBox'; +import { isInsideParent } from './utils'; const langSupport = Object.freeze({ javascript: javascript(), @@ -51,8 +53,17 @@ const MultiLineCodeEditor = (props) => { renderCopilot, } = props; const replaceIdsWithName = useStore((state) => state.replaceIdsWithName, shallow); + const wrapperRef = useRef(null); const getSuggestions = useStore((state) => state.getSuggestions, shallow); + const license = useStore((state) => state.license, shallow); + const isLicenseValid = + !_.get(license, 'featureAccess.licenseStatus.isExpired', true) && + _.get(license, 'featureAccess.licenseStatus.isLicenseValid', false); const isInsideQueryPane = !!document.querySelector('.code-hinter-wrapper')?.closest('.query-details'); + const isInsideQueryManager = useMemo( + () => isInsideParent(wrapperRef?.current, 'query-manager'), + [wrapperRef.current] + ); const context = useContext(CodeHinterContext); @@ -100,9 +111,27 @@ const MultiLineCodeEditor = (props) => { const hints = getSuggestions(); + const serverHints = []; + + if (isInsideQueryManager && isLicenseValid) { + hints?.appHints?.forEach((appHint) => { + if (appHint?.hint?.startsWith('globals.currentUser')) { + const key = appHint?.hint?.replace('globals.currentUser', 'globals.server.currentUser'); + serverHints.push({ + hint: key, + type: appHint?.type, + }); + } + }); + } + const allHints = { + ...hints, + appHints: [...hints.appHints, ...serverHints], + }; + let JSLangHints = []; if (lang === 'javascript') { - JSLangHints = Object.keys(hints['jsHints']) + JSLangHints = Object.keys(allHints['jsHints']) .map((key) => { return hints['jsHints'][key]['methods'].map((hint) => ({ hint: hint, @@ -120,7 +149,7 @@ const MultiLineCodeEditor = (props) => { }); } - const appHints = hints['appHints']; + const appHints = allHints['appHints']; let autoSuggestionList = appHints.filter((suggestion) => { return suggestion.hint.includes(nearestSubstring); @@ -229,6 +258,7 @@ const MultiLineCodeEditor = (props) => {
diff --git a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx index 2429973c25..89626cf820 100644 --- a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx +++ b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx @@ -96,6 +96,7 @@ export const PreviewBox = ({ const [largeDataset, setLargeDataset] = useState(false); const globals = useStore((state) => state.getAllExposedValues().constants || {}, shallow); const secrets = useStore((state) => state.getSecrets(), shallow); + const globalServerConstantsRegex = /.*\{\{.*globals\.server\..*\}\}.*/; const getPreviewContent = (content, type) => { if (content === undefined || content === null) return currentValue; @@ -118,11 +119,11 @@ export const PreviewBox = ({ let previewContent = resolvedValue; let isGlobalConstant = currentValue && currentValue.includes('{{constants.'); let isSecretConstant = currentValue && currentValue.includes('{{secrets.'); + const isServerConstant = currentValue && currentValue.match(globalServerConstantsRegex); let invalidConstants = null; let undefinedError = null; if (isGlobalConstant || isSecretConstant) { invalidConstants = verifyConstant(currentValue, globals, secrets); - console.log('invalidConstants', invalidConstants); } if (invalidConstants?.length) { undefinedError = { type: 'Invalid constants' }; @@ -222,6 +223,7 @@ export const PreviewBox = ({ isWorkspaceVariable={isWorkspaceVariable} isSecretConstant={isSecretConstant || false} isLargeDataset={largeDataset} + isServerConstant={isServerConstant} /> copyToClipboard(error ? error?.value : content)} @@ -240,6 +242,7 @@ const RenderResolvedValue = ({ withValidation, isWorkspaceVariable, isSecretConstant = false, + isServerConstant = false, isLargeDataset, }) => { const computeCoersionPreview = (resolvedValue, coersionData) => { @@ -264,7 +267,9 @@ const RenderResolvedValue = ({ }` : previewType; - const previewContent = isSecretConstant + const previewContent = isServerConstant + ? 'Server constants would be resolved at runtime' + : isSecretConstant ? 'Values of secret constants are hidden' : !withValidation ? resolvedValue diff --git a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx index 1243f26f43..74ed22a4f2 100644 --- a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx +++ b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx @@ -3,7 +3,7 @@ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; import { PreviewBox } from './PreviewBox'; import { ToolTip } from '@/Editor/Inspector/Elements/Components/ToolTip'; import { useTranslation } from 'react-i18next'; -import { camelCase, isEmpty, noop } from 'lodash'; +import { camelCase, isEmpty, noop, get } from 'lodash'; import CodeMirror from '@uiw/react-codemirror'; import { javascript } from '@codemirror/lang-javascript'; import { autocompletion, completionKeymap, completionStatus, acceptCompletion } from '@codemirror/autocomplete'; @@ -12,7 +12,7 @@ import { keymap } from '@codemirror/view'; import FxButton from '../CodeBuilder/Elements/FxButton'; import cx from 'classnames'; import { DynamicFxTypeRenderer } from './DynamicFxTypeRenderer'; -import { resolveReferences } from './utils'; +import { isInsideParent, resolveReferences } from './utils'; import { okaidia } from '@uiw/codemirror-theme-okaidia'; import { githubLight } from '@uiw/codemirror-theme-github'; import { getAutocompletion } from './autocompleteExtensionConfig'; @@ -136,6 +136,7 @@ const SingleLineCodeEditor = ({ componentName, fieldMeta = {}, componentId, ...r componentName={componentName} setShowPreview={setShowPreview} showPreview={showPreview} + wrapperRef={wrapperRef} {...restProps} />
@@ -168,10 +169,39 @@ const EditorInput = ({ previewRef, setShowPreview, onInputChange, + wrapperRef, }) => { + const license = useStore((state) => state.license, shallow); + + const isLicenseValid = + !get(license, 'featureAccess.licenseStatus.isExpired', true) && + get(license, 'featureAccess.licenseStatus.isLicenseValid', false); + const getSuggestions = useStore((state) => state.getSuggestions, shallow); + const isInsideQueryManager = useMemo( + () => isInsideParent(wrapperRef?.current, 'query-manager'), + [wrapperRef.current] + ); function autoCompleteExtensionConfig(context) { const hints = getSuggestions(); + const serverHints = []; + + if (isInsideQueryManager && isLicenseValid) { + hints?.appHints?.forEach((appHint) => { + if (appHint?.hint?.startsWith('globals.currentUser')) { + const key = appHint?.hint?.replace('globals.currentUser', 'globals.server.currentUser'); + serverHints.push({ + hint: key, + type: appHint?.type, + }); + } + }); + } + const allHints = { + ...hints, + appHints: [...hints.appHints, ...serverHints], + }; + let word = context.matchBefore(/\w*/); const totalReferences = (context.state.doc.toString().match(/{{/g) || []).length; @@ -202,7 +232,7 @@ const EditorInput = ({ queryInput = '{{' + currentWord + '}}'; } - let completions = getAutocompletion(queryInput, validationType, hints, totalReferences, originalQueryInput); + let completions = getAutocompletion(queryInput, validationType, allHints, totalReferences, originalQueryInput); return { from: word.from, @@ -212,7 +242,7 @@ const EditorInput = ({ } // eslint-disable-next-line react-hooks/exhaustive-deps - const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), []); + const overRideFunction = React.useCallback((context) => autoCompleteExtensionConfig(context), [isInsideQueryManager]); const autoCompleteConfig = autocompletion({ override: [overRideFunction], diff --git a/frontend/src/AppBuilder/CodeEditor/utils.js b/frontend/src/AppBuilder/CodeEditor/utils.js index 03473a629f..5149ece110 100644 --- a/frontend/src/AppBuilder/CodeEditor/utils.js +++ b/frontend/src/AppBuilder/CodeEditor/utils.js @@ -30,6 +30,17 @@ function traverseAST(node, callback) { } } +export const isInsideParent = (element, className) => { + while (element) { + if (element.classList?.contains(className)) { + console.log('element.classList', element.classList); + return true; + } + element = element.parentElement; + } + return false; +}; + function getMethods(type) { const arrayMethods = Object.getOwnPropertyNames(Array.prototype).filter( (p) => typeof Array.prototype[p] === 'function' diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 92712693b3..7621dc993d 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -122,7 +122,7 @@ module.exports = { '@cloud/modules': emptyModulePath, }, }, - devtool: environment === 'development' ? 'eval-source-map' : 'hidden-source-map', + devtool: 'source-map', module: { rules: [ { diff --git a/server/ee b/server/ee index 1da04eef69..003d8503fa 160000 --- a/server/ee +++ b/server/ee @@ -1 +1 @@ -Subproject commit 1da04eef696345ce9f35d42af92e5d6de992cd85 +Subproject commit 003d8503fa94f149d209e42198e934b1fb56e0bc diff --git a/server/src/modules/data-queries/interfaces/IUtilService.ts b/server/src/modules/data-queries/interfaces/IUtilService.ts index 738108d75d..2c390313df 100644 --- a/server/src/modules/data-queries/interfaces/IUtilService.ts +++ b/server/src/modules/data-queries/interfaces/IUtilService.ts @@ -22,7 +22,8 @@ export interface IDataQueriesUtilService { dataQuery: any, queryOptions: object, organization_id: string, - environmentId?: string + environmentId?: string, + userId?: string ): Promise<{ service: any; sourceOptions: object; diff --git a/server/src/modules/data-queries/util.service.ts b/server/src/modules/data-queries/util.service.ts index 889b39046d..08efbaa42b 100644 --- a/server/src/modules/data-queries/util.service.ts +++ b/server/src/modules/data-queries/util.service.ts @@ -82,6 +82,7 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { organizationId, environmentId ); + const userId = user ? user.id : null; dataSource.options = dataSourceOptions.options; let { sourceOptions, parsedQueryOptions, service } = await this.fetchServiceAndParsedParams( @@ -89,7 +90,8 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { dataQuery, queryOptions, organizationId, - environmentId + environmentId, + userId ); queryStatus.setOptions(parsedQueryOptions); @@ -217,7 +219,8 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { dataQuery, queryOptions, organizationId, - environmentId + environmentId, + userId )); queryStatus.setOptions(parsedQueryOptions); result = await service.run( @@ -291,18 +294,27 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { } } - async fetchServiceAndParsedParams(dataSource, dataQuery, queryOptions, organization_id, environmentId = undefined) { + async fetchServiceAndParsedParams( + dataSource, + dataQuery, + queryOptions, + organization_id, + environmentId = undefined, + userId = undefined + ) { const sourceOptions = await this.dataSourceUtilService.parseSourceOptions( dataSource.options, organization_id, - environmentId + environmentId, + userId ); const parsedQueryOptions = await this.parseQueryOptions( dataQuery.options, queryOptions, organization_id, - environmentId + environmentId, + userId ); const service = await this.pluginsSelectorService.getService(dataSource.pluginId, dataSource.kind); @@ -368,7 +380,8 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { object: any, options: object, organization_id: string, - environmentId?: string + environmentId?: string, + userId?: string ): Promise { const stack: any[] = [{ obj: object, key: null, parent: null }]; @@ -406,12 +419,14 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { // b: Handle {{constants.}} or {{secrets.}} if ( (typeof resolvedValue === 'string' && resolvedValue.includes('{{constants.')) || - resolvedValue.includes('{{secrets.') + resolvedValue.includes('{{secrets.') || + resolvedValue.includes('{{globals.server.') ) { const resolvingConstant = await this.dataSourceUtilService.resolveConstants( resolvedValue, organization_id, - environmentId + environmentId, + userId ); resolvedValue = resolvingConstant; if (parent && key !== null) { diff --git a/server/src/modules/data-sources/interfaces/IUtilService.ts b/server/src/modules/data-sources/interfaces/IUtilService.ts index f8db416617..8c72b78ddf 100644 --- a/server/src/modules/data-sources/interfaces/IUtilService.ts +++ b/server/src/modules/data-sources/interfaces/IUtilService.ts @@ -34,7 +34,7 @@ export interface IDataSourcesUtilService { parseOptionsForOauthDataSource(options: Array, resetSecureData?: boolean): Promise>; - resolveConstants(value: string, organizationId: string, environmentId: string): Promise; + resolveConstants(value: string, organizationId: string, environmentId: string, userId?: string): Promise; resolveKeyValuePair(element: any, organizationId: string, environmentId: string): Promise; diff --git a/server/src/modules/data-sources/module.ts b/server/src/modules/data-sources/module.ts index 27072f6d2c..0a17074118 100644 --- a/server/src/modules/data-sources/module.ts +++ b/server/src/modules/data-sources/module.ts @@ -10,6 +10,7 @@ import { InstanceSettingsModule } from '@modules/instance-settings/module'; import { VersionRepository } from '@modules/versions/repository'; import { AppsRepository } from '@modules/apps/repository'; import { TooljetDbModule } from '@modules/tooljet-db/module'; +import { UsersModule } from '@modules/users/module'; export class DataSourcesModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { @@ -28,6 +29,7 @@ export class DataSourcesModule { await OrganizationConstantModule.register(configs), await InstanceSettingsModule.register(configs), await TooljetDbModule.register(configs), + await UsersModule.register(configs), ], providers: [ DataSourcesService, diff --git a/server/src/modules/data-sources/util.service.ts b/server/src/modules/data-sources/util.service.ts index b4329dd4c5..8c89662f9f 100644 --- a/server/src/modules/data-sources/util.service.ts +++ b/server/src/modules/data-sources/util.service.ts @@ -302,8 +302,9 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { return dataSource; } - async resolveConstants(str: string, organizationId: string, environmentId: string): Promise { + async resolveConstants(str: string, organizationId: string, environmentId: string, userId?: string): Promise { const regex = /\{\{(constants|secrets)\.(.*?)\}\}/g; + const matches = Array.from(str.matchAll(regex)); if (matches.length === 0) return str; @@ -353,7 +354,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { } async resolveValue(value, organization_id, environment_id) { - const constantMatcher = /{{constants|secrets\..+?}}/g; + const constantMatcher = /{{constants|secrets|globals.server\..+?}}/g; if (typeof value === 'string' && constantMatcher.test(value)) { return await this.resolveConstants(value, organization_id, environment_id); @@ -371,7 +372,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { const parsedOptions = JSON.parse(JSON.stringify(options)); // need to match if currentOption is a contant, {{constants.psql_db} - const constantMatcher = /{{constants|secrets\..+?}}/g; + const constantMatcher = /{{constants|secrets|globals.server\..+?}}/g; for (const key of Object.keys(parsedOptions)) { let currentOption = parsedOptions[key]?.['value']; @@ -590,10 +591,15 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { return options; } - async parseSourceOptions(options: any, organizationId: string, environmentId: string): Promise { + async parseSourceOptions( + options: any, + organizationId: string, + environmentId: string, + userId?: string + ): Promise { // For adhoc queries such as REST API queries, source options will be null if (!options) return {}; - const constantMatcher = /\{\{(constants|secrets)\..*?\}\}/g; + const constantMatcher = /\{\{(constants|secrets|globals.server)\..*?\}\}/g; for (const key of Object.keys(options)) { const currentOption = options[key]?.['value']; @@ -609,7 +615,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { constantMatcher.lastIndex = 0; if (constantMatcher.test(inner)) { - const resolved = await this.resolveConstants(inner, organizationId, environmentId); + const resolved = await this.resolveConstants(inner, organizationId, environmentId, userId); curr[j] = resolved; } } @@ -618,7 +624,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { } if (constantMatcher.test(currentOption)) { - const resolved = await this.resolveConstants(currentOption, organizationId, environmentId); + const resolved = await this.resolveConstants(currentOption, organizationId, environmentId, userId); options[key]['value'] = resolved; } } @@ -633,7 +639,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { const value = await this.credentialService.getValue(credentialId); if (value.includes('{{constants') || value.includes('{{secrets')) { - const resolved = await this.resolveConstants(value, organizationId, environmentId); + const resolved = await this.resolveConstants(value, organizationId, environmentId, userId); parsedOptions[key] = resolved; continue; } else { diff --git a/server/src/modules/licensing/configs/LicenseBase.ts b/server/src/modules/licensing/configs/LicenseBase.ts index 6f7764addd..8b616a8d21 100644 --- a/server/src/modules/licensing/configs/LicenseBase.ts +++ b/server/src/modules/licensing/configs/LicenseBase.ts @@ -15,6 +15,7 @@ export default class LicenseBase { private _isCustomStyling: boolean; private _isWhiteLabelling: boolean; private _isCustomThemes: boolean; + private _isServerSideGlobal: boolean; private _isMultiEnvironment: boolean; private _isMultiPlayerEdit: boolean; private _isComments: boolean; @@ -49,6 +50,7 @@ export default class LicenseBase { this._isCustomStyling = true; this._isWhiteLabelling = true; this._isCustomThemes = true; + this._isServerSideGlobal = true; this._isLicenseValid = true; this._isMultiEnvironment = true; this._isAi = true; @@ -88,6 +90,7 @@ export default class LicenseBase { this._isCustomStyling = this.getFeatureValue('customStyling'); this._isWhiteLabelling = this.getFeatureValue('whiteLabelling'); this._isCustomThemes = this.getFeatureValue('customThemes'); + this._isServerSideGlobal = this.getFeatureValue('serverSideGlobal'); this._isMultiEnvironment = this.getFeatureValue('multiEnvironment'); this._isMultiPlayerEdit = this.getFeatureValue('multiPlayerEdit'); this._isComments = this.getFeatureValue('comments'); @@ -256,6 +259,13 @@ export default class LicenseBase { return this._isCustomThemes; } + public get serverSideGlobal(): boolean { + if (this.IsBasicPlan) { + return !!BASIC_PLAN_TERMS.features?.serverSideGlobal; + } + return this._isServerSideGlobal; + } + public get multiPlayerEdit(): boolean { if (this.IsBasicPlan) { return !!BASIC_PLAN_TERMS.features?.multiPlayerEdit; @@ -298,6 +308,7 @@ export default class LicenseBase { customStyling: this.customStyling, whiteLabelling: this.whiteLabelling, customThemes: this.customThemes, + serverSideGlobal: this.serverSideGlobal, multiEnvironment: this.multiEnvironment, multiPlayerEdit: this.multiPlayerEdit, gitSync: this.gitSync, @@ -326,6 +337,7 @@ export default class LicenseBase { samlEnabled: this.saml, customStylingEnabled: this.customStyling, customThemesEnabled: this.customThemes, + serverSideGlobalEnabled: this.serverSideGlobal, multiEnvironmentEnabled: this.multiEnvironment, multiPlayerEditEnabled: this.multiPlayerEdit, commentsEnabled: this.comments, diff --git a/server/src/modules/licensing/constants/PlanTerms.ts b/server/src/modules/licensing/constants/PlanTerms.ts index 0eb05cfe6c..c896a1aa46 100644 --- a/server/src/modules/licensing/constants/PlanTerms.ts +++ b/server/src/modules/licensing/constants/PlanTerms.ts @@ -25,6 +25,7 @@ export const BASIC_PLAN_TERMS: Partial = { gitSync: false, comments: false, customThemes: false, + serverSideGlobal: false, ai: true, }, domains: [], diff --git a/server/src/modules/licensing/constants/index.ts b/server/src/modules/licensing/constants/index.ts index 49c7428a84..f5bcf3bd14 100644 --- a/server/src/modules/licensing/constants/index.ts +++ b/server/src/modules/licensing/constants/index.ts @@ -104,6 +104,7 @@ export enum LICENSE_FIELD { CUSTOM_STYLE = 'customStylingEnabled', WHITE_LABEL = 'whitelabellingEnabled', CUSTOM_THEMES = 'customThemeEnabled', + SERVER_SIDE_GLOBAL = 'serverSideGlobalEnabled', AUDIT_LOGS = 'auditLogsEnabled', MAX_DURATION_FOR_AUDIT_LOGS = 'maxDaysForAuditLogs', MULTI_ENVIRONMENT = 'multiEnvironmentEnabled', diff --git a/server/src/modules/licensing/helper.ts b/server/src/modules/licensing/helper.ts index a9ffdc3305..fb6a10bf4e 100644 --- a/server/src/modules/licensing/helper.ts +++ b/server/src/modules/licensing/helper.ts @@ -59,6 +59,9 @@ export function getLicenseFieldValue(type: LICENSE_FIELD, licenseInstance: Licen case LICENSE_FIELD.CUSTOM_THEMES: return licenseInstance.customThemes; + // case LICENSE_FIELD.SERVER_SIDE_GLOBAL: + // return licenseInstance.serverSideGlobal; + case LICENSE_FIELD.AUDIT_LOGS: return licenseInstance.auditLogs; diff --git a/server/src/modules/licensing/interfaces/terms.ts b/server/src/modules/licensing/interfaces/terms.ts index 5be1902aef..c7cbb86690 100644 --- a/server/src/modules/licensing/interfaces/terms.ts +++ b/server/src/modules/licensing/interfaces/terms.ts @@ -27,6 +27,7 @@ export interface Terms { gitSync?: boolean; comments?: boolean; customThemes?: boolean; + serverSideGlobal?: boolean; ai?: boolean; }; type?: LICENSE_TYPE; diff --git a/server/src/modules/organization-constants/constants/index.ts b/server/src/modules/organization-constants/constants/index.ts index edd867b913..7ed5e37bca 100644 --- a/server/src/modules/organization-constants/constants/index.ts +++ b/server/src/modules/organization-constants/constants/index.ts @@ -1,6 +1,7 @@ export enum OrganizationConstantType { GLOBAL = 'Global', SECRET = 'Secret', + SERVER = 'Server', } export enum FEATURE_KEY { diff --git a/server/src/modules/organization-users/module.ts b/server/src/modules/organization-users/module.ts index 174c1b8a92..3ebec059aa 100644 --- a/server/src/modules/organization-users/module.ts +++ b/server/src/modules/organization-users/module.ts @@ -20,7 +20,9 @@ export class OrganizationUsersModule { const { OrganizationUsersController } = await import( `${await getImportPath(IS_GET_CONTEXT)}/organization-users/controller` ); - const { OrganizationUsersService } = await import(`${await getImportPath(IS_GET_CONTEXT)}/organization-users/service`); + const { OrganizationUsersService } = await import( + `${await getImportPath(IS_GET_CONTEXT)}/organization-users/service` + ); const { OrganizationUsersUtilService } = await import( `${await getImportPath(IS_GET_CONTEXT)}/organization-users/util.service` ); diff --git a/server/src/modules/users/module.ts b/server/src/modules/users/module.ts index bd91972dba..965856b0d8 100644 --- a/server/src/modules/users/module.ts +++ b/server/src/modules/users/module.ts @@ -3,6 +3,15 @@ import { DynamicModule } from '@nestjs/common'; import { UserRepository } from './repository'; import { SessionModule } from '@modules/session/module'; import { FeatureAbilityFactory } from './ability'; +import { SessionUtilService } from '@modules/session/util.service'; +import { OrganizationRepository } from '@modules/organizations/repository'; +import { GroupPermissionsRepository } from '@modules/group-permissions/repository'; +import { OrganizationUsersRepository } from '@modules/organization-users/repository'; +import { MetadataUtilService } from '@modules/meta/util.service'; +import { RolesRepository } from '@modules/roles/repository'; +import { EncryptionService } from '@modules/encryption/service'; +import { JwtService } from '@nestjs/jwt'; +import { LicenseCountsService } from '@modules/licensing/services/count.service'; export class UsersModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { @@ -15,7 +24,22 @@ export class UsersModule { module: UsersModule, imports: [await SessionModule.register(configs)], controllers: [UsersController], - providers: [UsersService, UserRepository, UsersUtilService, FeatureAbilityFactory], + providers: [ + UsersService, + UserRepository, + UsersUtilService, + FeatureAbilityFactory, + SessionUtilService, + OrganizationRepository, + OrganizationUsersRepository, + GroupPermissionsRepository, + MetadataUtilService, + RolesRepository, + EncryptionService, + JwtService, + LicenseCountsService, + ], + exports: [UsersUtilService, UserRepository], }; } } From 3b5c6a148610a705ea2a976e15fe006abafe2fc5 Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Wed, 2 Apr 2025 02:11:13 +0530 Subject: [PATCH 2/8] Minor fixes and code adjustments --- .../CodeEditor/MultiLineCodeEditor.jsx | 19 ++--------- .../src/AppBuilder/CodeEditor/PreviewBox.jsx | 6 +++- .../CodeEditor/SingleLineCodeEditor.jsx | 19 ++--------- .../_stores/slices/codeHinterSlice.js | 18 ++++++++++ frontend/webpack.config.js | 2 +- server/ee | 2 +- server/src/modules/licensing/helper.ts | 4 +-- server/src/modules/organizations/module.ts | 1 + server/src/modules/users/module.ts | 33 +++++-------------- 9 files changed, 41 insertions(+), 63 deletions(-) diff --git a/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx b/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx index b447df7efd..ef5a5dbd7d 100644 --- a/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx +++ b/frontend/src/AppBuilder/CodeEditor/MultiLineCodeEditor.jsx @@ -55,10 +55,8 @@ const MultiLineCodeEditor = (props) => { const replaceIdsWithName = useStore((state) => state.replaceIdsWithName, shallow); const wrapperRef = useRef(null); const getSuggestions = useStore((state) => state.getSuggestions, shallow); - const license = useStore((state) => state.license, shallow); - const isLicenseValid = - !_.get(license, 'featureAccess.licenseStatus.isExpired', true) && - _.get(license, 'featureAccess.licenseStatus.isLicenseValid', false); + const getServerSideGlobalSuggestions = useStore((state) => state.getServerSideGlobalSuggestions, shallow); + const isInsideQueryPane = !!document.querySelector('.code-hinter-wrapper')?.closest('.query-details'); const isInsideQueryManager = useMemo( () => isInsideParent(wrapperRef?.current, 'query-manager'), @@ -111,19 +109,8 @@ const MultiLineCodeEditor = (props) => { const hints = getSuggestions(); - const serverHints = []; + const serverHints = getServerSideGlobalSuggestions(isInsideQueryManager); - if (isInsideQueryManager && isLicenseValid) { - hints?.appHints?.forEach((appHint) => { - if (appHint?.hint?.startsWith('globals.currentUser')) { - const key = appHint?.hint?.replace('globals.currentUser', 'globals.server.currentUser'); - serverHints.push({ - hint: key, - type: appHint?.type, - }); - } - }); - } const allHints = { ...hints, appHints: [...hints.appHints, ...serverHints], diff --git a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx index 89626cf820..bc8411752a 100644 --- a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx +++ b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx @@ -198,7 +198,11 @@ export const PreviewBox = ({ const errValue = ifCoersionErrorHasCircularDependency(_resolveValue); setError({ - message: isSecretError ? 'secrets cannot be used in apps' : _error, + message: isServerConstant + ? 'Server side variables cannot be used in apps' + : isSecretError + ? 'secrets cannot be used in apps' + : _error, value: isSecretError ? 'Undefined' : jsErrorType === 'Invalid' diff --git a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx index 74ed22a4f2..e0d0203fd2 100644 --- a/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx +++ b/frontend/src/AppBuilder/CodeEditor/SingleLineCodeEditor.jsx @@ -171,11 +171,7 @@ const EditorInput = ({ onInputChange, wrapperRef, }) => { - const license = useStore((state) => state.license, shallow); - - const isLicenseValid = - !get(license, 'featureAccess.licenseStatus.isExpired', true) && - get(license, 'featureAccess.licenseStatus.isLicenseValid', false); + const getServerSideGlobalSuggestions = useStore((state) => state.getServerSideGlobalSuggestions, shallow); const getSuggestions = useStore((state) => state.getSuggestions, shallow); const isInsideQueryManager = useMemo( @@ -184,19 +180,8 @@ const EditorInput = ({ ); function autoCompleteExtensionConfig(context) { const hints = getSuggestions(); - const serverHints = []; + const serverHints = getServerSideGlobalSuggestions(isInsideQueryManager); - if (isInsideQueryManager && isLicenseValid) { - hints?.appHints?.forEach((appHint) => { - if (appHint?.hint?.startsWith('globals.currentUser')) { - const key = appHint?.hint?.replace('globals.currentUser', 'globals.server.currentUser'); - serverHints.push({ - hint: key, - type: appHint?.type, - }); - } - }); - } const allHints = { ...hints, appHints: [...hints.appHints, ...serverHints], diff --git a/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js b/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js index 953d253709..5933a727f1 100644 --- a/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js @@ -36,4 +36,22 @@ export const createCodeHinterSlice = (set, get) => ({ setSuggestions({ appHints: suggestionList, jsHints: jsHints }); }, getSuggestions: () => get().suggestions, + getServerSideGlobalSuggestions: (isInsideQueryManager) => { + const isServerSideGlobalEnabled = !!get()?.license?.featureAccess?.serverSideGlobal; + const serverHints = []; + const hints = get().getSuggestions(); + if (isInsideQueryManager && isServerSideGlobalEnabled) { + hints?.appHints?.forEach((appHint) => { + if (appHint?.hint?.startsWith('globals.currentUser')) { + const key = appHint?.hint?.replace('globals.currentUser', 'globals.server.currentUser'); + serverHints.push({ + hint: key, + type: appHint?.type, + }); + } + }); + } + + return serverHints; + }, }); diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 7621dc993d..986c7011b1 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -122,7 +122,7 @@ module.exports = { '@cloud/modules': emptyModulePath, }, }, - devtool: 'source-map', + devtool: environment === 'development' ? 'source-map' : 'hidden-source-map', module: { rules: [ { diff --git a/server/ee b/server/ee index 003d8503fa..7701ae87d3 160000 --- a/server/ee +++ b/server/ee @@ -1 +1 @@ -Subproject commit 003d8503fa94f149d209e42198e934b1fb56e0bc +Subproject commit 7701ae87d3698f1acc42b26bf6144507bf7beb0d diff --git a/server/src/modules/licensing/helper.ts b/server/src/modules/licensing/helper.ts index fb6a10bf4e..0a8bc949b5 100644 --- a/server/src/modules/licensing/helper.ts +++ b/server/src/modules/licensing/helper.ts @@ -59,8 +59,8 @@ export function getLicenseFieldValue(type: LICENSE_FIELD, licenseInstance: Licen case LICENSE_FIELD.CUSTOM_THEMES: return licenseInstance.customThemes; - // case LICENSE_FIELD.SERVER_SIDE_GLOBAL: - // return licenseInstance.serverSideGlobal; + case LICENSE_FIELD.SERVER_SIDE_GLOBAL: + return licenseInstance.serverSideGlobal; case LICENSE_FIELD.AUDIT_LOGS: return licenseInstance.auditLogs; diff --git a/server/src/modules/organizations/module.ts b/server/src/modules/organizations/module.ts index b7432d5e4c..c455f68d38 100644 --- a/server/src/modules/organizations/module.ts +++ b/server/src/modules/organizations/module.ts @@ -16,6 +16,7 @@ export class OrganizationsModule { imports: [await InstanceSettingsModule.register(configs)], controllers: [OrganizationsController], providers: [OrganizationsService, OrganizationRepository, FeatureAbilityFactory, AppEnvironmentUtilService], + exports: [OrganizationRepository], }; } } diff --git a/server/src/modules/users/module.ts b/server/src/modules/users/module.ts index 965856b0d8..753484e802 100644 --- a/server/src/modules/users/module.ts +++ b/server/src/modules/users/module.ts @@ -3,15 +3,8 @@ import { DynamicModule } from '@nestjs/common'; import { UserRepository } from './repository'; import { SessionModule } from '@modules/session/module'; import { FeatureAbilityFactory } from './ability'; -import { SessionUtilService } from '@modules/session/util.service'; -import { OrganizationRepository } from '@modules/organizations/repository'; -import { GroupPermissionsRepository } from '@modules/group-permissions/repository'; -import { OrganizationUsersRepository } from '@modules/organization-users/repository'; -import { MetadataUtilService } from '@modules/meta/util.service'; -import { RolesRepository } from '@modules/roles/repository'; -import { EncryptionService } from '@modules/encryption/service'; -import { JwtService } from '@nestjs/jwt'; -import { LicenseCountsService } from '@modules/licensing/services/count.service'; +import { OrganizationsModule } from '@modules/organizations/module'; +import { MetaModule } from '@modules/meta/module'; export class UsersModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { @@ -22,23 +15,13 @@ export class UsersModule { return { module: UsersModule, - imports: [await SessionModule.register(configs)], - controllers: [UsersController], - providers: [ - UsersService, - UserRepository, - UsersUtilService, - FeatureAbilityFactory, - SessionUtilService, - OrganizationRepository, - OrganizationUsersRepository, - GroupPermissionsRepository, - MetadataUtilService, - RolesRepository, - EncryptionService, - JwtService, - LicenseCountsService, + imports: [ + await SessionModule.register(configs), + await OrganizationsModule.register(configs), + await MetaModule.register(configs), ], + controllers: [UsersController], + providers: [UsersService, UserRepository, UsersUtilService, FeatureAbilityFactory], exports: [UsersUtilService, UserRepository], }; } From 9632939beaa26c3ab8ce6f862e139d0df867efcd Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Wed, 2 Apr 2025 03:23:34 +0530 Subject: [PATCH 3/8] Minor changes --- server/ee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/ee b/server/ee index 7701ae87d3..26c75a6d49 160000 --- a/server/ee +++ b/server/ee @@ -1 +1 @@ -Subproject commit 7701ae87d3698f1acc42b26bf6144507bf7beb0d +Subproject commit 26c75a6d49101e500074f9dde5b1bec99a4093bd From abde48b5e0ba23b71eaea4b6f42ecead17affba2 Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Fri, 4 Apr 2025 00:27:59 +0530 Subject: [PATCH 4/8] Resolved comments --- .../data-queries/interfaces/IUtilService.ts | 10 ++++++++-- server/src/modules/data-queries/util.service.ts | 15 +++++++-------- .../data-sources/interfaces/IUtilService.ts | 2 +- server/src/modules/data-sources/module.ts | 2 ++ server/src/modules/data-sources/util.service.ts | 15 +++++---------- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/server/src/modules/data-queries/interfaces/IUtilService.ts b/server/src/modules/data-queries/interfaces/IUtilService.ts index 2c390313df..f070380b54 100644 --- a/server/src/modules/data-queries/interfaces/IUtilService.ts +++ b/server/src/modules/data-queries/interfaces/IUtilService.ts @@ -23,7 +23,7 @@ export interface IDataQueriesUtilService { queryOptions: object, organization_id: string, environmentId?: string, - userId?: string + user?: User ): Promise<{ service: any; sourceOptions: object; @@ -32,5 +32,11 @@ export interface IDataQueriesUtilService { setCookiesBackToClient(response: Response, responseHeaders: any): void; - parseQueryOptions(object: any, options: object, organization_id: string, environmentId?: string): Promise; + parseQueryOptions( + object: any, + options: object, + organization_id: string, + environmentId?: string, + user?: User + ): Promise; } diff --git a/server/src/modules/data-queries/util.service.ts b/server/src/modules/data-queries/util.service.ts index 08efbaa42b..f99fb84718 100644 --- a/server/src/modules/data-queries/util.service.ts +++ b/server/src/modules/data-queries/util.service.ts @@ -82,7 +82,6 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { organizationId, environmentId ); - const userId = user ? user.id : null; dataSource.options = dataSourceOptions.options; let { sourceOptions, parsedQueryOptions, service } = await this.fetchServiceAndParsedParams( @@ -91,7 +90,7 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { queryOptions, organizationId, environmentId, - userId + user ); queryStatus.setOptions(parsedQueryOptions); @@ -220,7 +219,7 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { queryOptions, organizationId, environmentId, - userId + user )); queryStatus.setOptions(parsedQueryOptions); result = await service.run( @@ -300,13 +299,13 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { queryOptions, organization_id, environmentId = undefined, - userId = undefined + user = undefined ) { const sourceOptions = await this.dataSourceUtilService.parseSourceOptions( dataSource.options, organization_id, environmentId, - userId + user ); const parsedQueryOptions = await this.parseQueryOptions( @@ -314,7 +313,7 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { queryOptions, organization_id, environmentId, - userId + user ); const service = await this.pluginsSelectorService.getService(dataSource.pluginId, dataSource.kind); @@ -381,7 +380,7 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { options: object, organization_id: string, environmentId?: string, - userId?: string + user?: User ): Promise { const stack: any[] = [{ obj: object, key: null, parent: null }]; @@ -426,7 +425,7 @@ export class DataQueriesUtilService implements IDataQueriesUtilService { resolvedValue, organization_id, environmentId, - userId + user ); resolvedValue = resolvingConstant; if (parent && key !== null) { diff --git a/server/src/modules/data-sources/interfaces/IUtilService.ts b/server/src/modules/data-sources/interfaces/IUtilService.ts index 8c72b78ddf..1539d73019 100644 --- a/server/src/modules/data-sources/interfaces/IUtilService.ts +++ b/server/src/modules/data-sources/interfaces/IUtilService.ts @@ -34,7 +34,7 @@ export interface IDataSourcesUtilService { parseOptionsForOauthDataSource(options: Array, resetSecureData?: boolean): Promise>; - resolveConstants(value: string, organizationId: string, environmentId: string, userId?: string): Promise; + resolveConstants(value: string, organizationId: string, environmentId: string, user?: User): Promise; resolveKeyValuePair(element: any, organizationId: string, environmentId: string): Promise; diff --git a/server/src/modules/data-sources/module.ts b/server/src/modules/data-sources/module.ts index 0a17074118..f9d774ba78 100644 --- a/server/src/modules/data-sources/module.ts +++ b/server/src/modules/data-sources/module.ts @@ -11,6 +11,7 @@ import { VersionRepository } from '@modules/versions/repository'; import { AppsRepository } from '@modules/apps/repository'; import { TooljetDbModule } from '@modules/tooljet-db/module'; import { UsersModule } from '@modules/users/module'; +import { SessionModule } from '@modules/session/module'; export class DataSourcesModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { @@ -30,6 +31,7 @@ export class DataSourcesModule { await InstanceSettingsModule.register(configs), await TooljetDbModule.register(configs), await UsersModule.register(configs), + await SessionModule.register(configs), ], providers: [ DataSourcesService, diff --git a/server/src/modules/data-sources/util.service.ts b/server/src/modules/data-sources/util.service.ts index 8c89662f9f..28d5719ad1 100644 --- a/server/src/modules/data-sources/util.service.ts +++ b/server/src/modules/data-sources/util.service.ts @@ -302,7 +302,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { return dataSource; } - async resolveConstants(str: string, organizationId: string, environmentId: string, userId?: string): Promise { + async resolveConstants(str: string, organizationId: string, environmentId: string, user?: User): Promise { const regex = /\{\{(constants|secrets)\.(.*?)\}\}/g; const matches = Array.from(str.matchAll(regex)); @@ -591,12 +591,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { return options; } - async parseSourceOptions( - options: any, - organizationId: string, - environmentId: string, - userId?: string - ): Promise { + async parseSourceOptions(options: any, organizationId: string, environmentId: string, user?: User): Promise { // For adhoc queries such as REST API queries, source options will be null if (!options) return {}; const constantMatcher = /\{\{(constants|secrets|globals.server)\..*?\}\}/g; @@ -615,7 +610,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { constantMatcher.lastIndex = 0; if (constantMatcher.test(inner)) { - const resolved = await this.resolveConstants(inner, organizationId, environmentId, userId); + const resolved = await this.resolveConstants(inner, organizationId, environmentId, user); curr[j] = resolved; } } @@ -624,7 +619,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { } if (constantMatcher.test(currentOption)) { - const resolved = await this.resolveConstants(currentOption, organizationId, environmentId, userId); + const resolved = await this.resolveConstants(currentOption, organizationId, environmentId, user); options[key]['value'] = resolved; } } @@ -639,7 +634,7 @@ export class DataSourcesUtilService implements IDataSourcesUtilService { const value = await this.credentialService.getValue(credentialId); if (value.includes('{{constants') || value.includes('{{secrets')) { - const resolved = await this.resolveConstants(value, organizationId, environmentId, userId); + const resolved = await this.resolveConstants(value, organizationId, environmentId, user); parsedOptions[key] = resolved; continue; } else { From a0a1480594d085ef4c70d53579407d2b6528f59e Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Fri, 4 Apr 2025 00:47:28 +0530 Subject: [PATCH 5/8] Unnecessary code removed --- server/src/modules/data-sources/module.ts | 2 -- server/src/modules/organizations/module.ts | 1 - server/src/modules/users/module.ts | 9 +-------- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/server/src/modules/data-sources/module.ts b/server/src/modules/data-sources/module.ts index f9d774ba78..e247ddba38 100644 --- a/server/src/modules/data-sources/module.ts +++ b/server/src/modules/data-sources/module.ts @@ -10,7 +10,6 @@ import { InstanceSettingsModule } from '@modules/instance-settings/module'; import { VersionRepository } from '@modules/versions/repository'; import { AppsRepository } from '@modules/apps/repository'; import { TooljetDbModule } from '@modules/tooljet-db/module'; -import { UsersModule } from '@modules/users/module'; import { SessionModule } from '@modules/session/module'; export class DataSourcesModule { @@ -30,7 +29,6 @@ export class DataSourcesModule { await OrganizationConstantModule.register(configs), await InstanceSettingsModule.register(configs), await TooljetDbModule.register(configs), - await UsersModule.register(configs), await SessionModule.register(configs), ], providers: [ diff --git a/server/src/modules/organizations/module.ts b/server/src/modules/organizations/module.ts index c455f68d38..b7432d5e4c 100644 --- a/server/src/modules/organizations/module.ts +++ b/server/src/modules/organizations/module.ts @@ -16,7 +16,6 @@ export class OrganizationsModule { imports: [await InstanceSettingsModule.register(configs)], controllers: [OrganizationsController], providers: [OrganizationsService, OrganizationRepository, FeatureAbilityFactory, AppEnvironmentUtilService], - exports: [OrganizationRepository], }; } } diff --git a/server/src/modules/users/module.ts b/server/src/modules/users/module.ts index 753484e802..bd91972dba 100644 --- a/server/src/modules/users/module.ts +++ b/server/src/modules/users/module.ts @@ -3,8 +3,6 @@ import { DynamicModule } from '@nestjs/common'; import { UserRepository } from './repository'; import { SessionModule } from '@modules/session/module'; import { FeatureAbilityFactory } from './ability'; -import { OrganizationsModule } from '@modules/organizations/module'; -import { MetaModule } from '@modules/meta/module'; export class UsersModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { @@ -15,14 +13,9 @@ export class UsersModule { return { module: UsersModule, - imports: [ - await SessionModule.register(configs), - await OrganizationsModule.register(configs), - await MetaModule.register(configs), - ], + imports: [await SessionModule.register(configs)], controllers: [UsersController], providers: [UsersService, UserRepository, UsersUtilService, FeatureAbilityFactory], - exports: [UsersUtilService, UserRepository], }; } } From 73f630668a91b146c15f5764da5312f0dd152b2d Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Fri, 4 Apr 2025 01:23:58 +0530 Subject: [PATCH 6/8] Minor bug fixes --- frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx | 2 +- frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx index bc8411752a..3ca9261a4b 100644 --- a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx +++ b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx @@ -96,7 +96,7 @@ export const PreviewBox = ({ const [largeDataset, setLargeDataset] = useState(false); const globals = useStore((state) => state.getAllExposedValues().constants || {}, shallow); const secrets = useStore((state) => state.getSecrets(), shallow); - const globalServerConstantsRegex = /.*\{\{.*globals\.server\..*\}\}.*/; + const globalServerConstantsRegex = /^\{\{.*globals\.server.*\}\}$/; const getPreviewContent = (content, type) => { if (content === undefined || content === null) return currentValue; diff --git a/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js b/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js index 5933a727f1..7f73632524 100644 --- a/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js @@ -40,10 +40,16 @@ export const createCodeHinterSlice = (set, get) => ({ const isServerSideGlobalEnabled = !!get()?.license?.featureAccess?.serverSideGlobal; const serverHints = []; const hints = get().getSuggestions(); + console.log('isServerSideGlobalEnabled', isServerSideGlobalEnabled, 'isInsideQueryManager', isInsideQueryManager); if (isInsideQueryManager && isServerSideGlobalEnabled) { + serverHints.push({ hint: 'globals.server', type: 'Object' }); hints?.appHints?.forEach((appHint) => { if (appHint?.hint?.startsWith('globals.currentUser')) { const key = appHint?.hint?.replace('globals.currentUser', 'globals.server.currentUser'); + console.log({ + hint: key, + type: appHint?.type, + }); serverHints.push({ hint: key, type: appHint?.type, From 2481bda0c83147dc8b9f2918c43b6e402988deb6 Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Fri, 4 Apr 2025 01:27:41 +0530 Subject: [PATCH 7/8] Comments removed --- frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js b/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js index 7f73632524..854cba49da 100644 --- a/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js +++ b/frontend/src/AppBuilder/_stores/slices/codeHinterSlice.js @@ -40,7 +40,6 @@ export const createCodeHinterSlice = (set, get) => ({ const isServerSideGlobalEnabled = !!get()?.license?.featureAccess?.serverSideGlobal; const serverHints = []; const hints = get().getSuggestions(); - console.log('isServerSideGlobalEnabled', isServerSideGlobalEnabled, 'isInsideQueryManager', isInsideQueryManager); if (isInsideQueryManager && isServerSideGlobalEnabled) { serverHints.push({ hint: 'globals.server', type: 'Object' }); hints?.appHints?.forEach((appHint) => { From c9a70058d34588962b425119d32d54bbf2e43aad Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Fri, 4 Apr 2025 15:39:02 +0530 Subject: [PATCH 8/8] Minor bug fixes --- frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx index 3ca9261a4b..90bc53d2b7 100644 --- a/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx +++ b/frontend/src/AppBuilder/CodeEditor/PreviewBox.jsx @@ -199,7 +199,7 @@ export const PreviewBox = ({ setError({ message: isServerConstant - ? 'Server side variables cannot be used in apps' + ? 'Server variables cannot be used in apps' : isSecretError ? 'secrets cannot be used in apps' : _error, @@ -249,6 +249,8 @@ const RenderResolvedValue = ({ isServerConstant = false, isLargeDataset, }) => { + const isServerSideGlobalEnabled = useStore((state) => !!state?.license?.featureAccess?.serverSideGlobal, shallow); + const computeCoersionPreview = (resolvedValue, coersionData) => { if (coersionData?.typeBeforeCoercion === coersionData?.typeAfterCoercion) return resolvedValue; @@ -272,7 +274,9 @@ const RenderResolvedValue = ({ : previewType; const previewContent = isServerConstant - ? 'Server constants would be resolved at runtime' + ? isServerSideGlobalEnabled + ? 'Server variables would be resolved at runtime' + : 'Server variables are only available in paid plans' : isSecretConstant ? 'Values of secret constants are hidden' : !withValidation