mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-06 06:48:21 +00:00
Merge branch 'main' into release/marketplace-sprint-12
This commit is contained in:
commit
a80fc752d8
13 changed files with 121 additions and 59 deletions
|
|
@ -42,6 +42,20 @@ else
|
|||
echo "Using external PostgREST at $PGRST_HOST."
|
||||
fi
|
||||
|
||||
|
||||
# Check WORKLOW_WORKER and skip SETUP_CMD if true
|
||||
if [ "${WORKFLOW_WORKER}" == "true" ]; then
|
||||
echo "WORKFLOW_WORKER is set to true. Running worker process."
|
||||
npm run worker:prod
|
||||
else
|
||||
# Determine setup command based on the presence of ./server/dist
|
||||
if [ -d "./server/dist" ]; then
|
||||
SETUP_CMD='npm run db:setup:prod'
|
||||
else
|
||||
SETUP_CMD='npm run db:setup'
|
||||
fi
|
||||
fi
|
||||
|
||||
# Neo4j configuration
|
||||
# ----------------------------------
|
||||
# Default Neo4j environment values
|
||||
|
|
@ -63,14 +77,14 @@ if [ -n "$NEO4J_AUTH" ]; then
|
|||
export NEO4J_USERNAME
|
||||
export NEO4J_PASSWORD
|
||||
|
||||
echo "Neo4j authentication configured with username: $NEO4J_USERNAME"
|
||||
echo "Neo4j authentication configured with username: $NEO4J_USERNAME" >/dev/null 2>&1
|
||||
else
|
||||
echo "NEO4J_AUTH not set, using default authentication"
|
||||
echo "NEO4J_AUTH not set, using default authentication" >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Check if Neo4j is already initialized and set password if necessary
|
||||
if [ "$NEO4J_AUTH" != "none" ] && [ -n "$NEO4J_PASSWORD" ]; then
|
||||
echo "Setting Neo4j initial password..."
|
||||
echo "Setting Neo4j initial password..." >/dev/null 2>&1
|
||||
|
||||
# Ensure Neo4j is not running before setting the initial password
|
||||
neo4j stop || true
|
||||
|
|
@ -78,27 +92,27 @@ if [ "$NEO4J_AUTH" != "none" ] && [ -n "$NEO4J_PASSWORD" ]; then
|
|||
# Set the initial password using the correct command format for Neo4j 5.x
|
||||
NEO4J_ADMIN_CMD=$(which neo4j-admin)
|
||||
NEO4J_VERSION=$(neo4j --version | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+" | head -n 1)
|
||||
echo "Detected Neo4j version: $NEO4J_VERSION"
|
||||
echo "Detected Neo4j version: $NEO4J_VERSION" >/dev/null 2>&1
|
||||
|
||||
# Use version-specific command format
|
||||
MAJOR_VERSION=$(echo $NEO4J_VERSION | cut -d. -f1)
|
||||
if [ "$MAJOR_VERSION" -ge "5" ]; then
|
||||
# For Neo4j 5.x and higher
|
||||
echo "Using Neo4j 5.x+ password command format"
|
||||
echo "Using Neo4j 5.x+ password command format" >/dev/null 2>&1
|
||||
$NEO4J_ADMIN_CMD dbms set-initial-password "$NEO4J_PASSWORD" --require-password-change=false >/dev/null 2>&1 || {
|
||||
echo "Warning: Could not set Neo4j password, it may already be set"
|
||||
echo "Warning: Could not set Neo4j password, it may already be set" >/dev/null 2>&1
|
||||
}
|
||||
else
|
||||
# For Neo4j 4.x and lower
|
||||
echo "Using Neo4j 4.x password command format" >/dev/null 2>&1
|
||||
$NEO4J_ADMIN_CMD set-initial-password "$NEO4J_PASSWORD" >/dev/null 2>&1 || {
|
||||
echo "Warning: Could not set Neo4j password, it may already be set"
|
||||
echo "Warning: Could not set Neo4j password, it may already be set" >/dev/null 2>&1
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Update Neo4j configuration
|
||||
echo "Configuring Neo4j..."
|
||||
echo "Configuring Neo4j..." >/dev/null 2>&1
|
||||
cat > /etc/neo4j/neo4j.conf << EOF
|
||||
# Neo4j configuration
|
||||
dbms.security.auth_enabled=true
|
||||
|
|
@ -124,12 +138,12 @@ echo "Starting Neo4j service..."
|
|||
neo4j console >/dev/null 2>&1 &
|
||||
|
||||
# Add a wait for Neo4j to be ready with more robust checking
|
||||
echo "Waiting for Neo4j to be ready..."
|
||||
echo "Waiting for Neo4j to be ready..." >/dev/null 2>&1
|
||||
NEO4J_READY=false
|
||||
for i in {1..60}; do
|
||||
# First try standard status check
|
||||
if neo4j status >/dev/null 2>&1; then
|
||||
echo "Neo4j is ready (via status check)"
|
||||
echo "Neo4j is ready 🚀"
|
||||
NEO4J_READY=true
|
||||
break
|
||||
fi
|
||||
|
|
@ -143,7 +157,7 @@ for i in {1..60}; do
|
|||
fi
|
||||
fi
|
||||
|
||||
echo "Waiting for Neo4j to start... ($i/60)"
|
||||
echo "Waiting for Neo4j to start... ($i/60)" >/dev/null 2>&1
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
|
@ -151,19 +165,6 @@ if [ "$NEO4J_READY" = false ]; then
|
|||
echo "WARNING: Neo4j may not be fully started yet, but continuing..."
|
||||
fi
|
||||
|
||||
# Check WORKLOW_WORKER and skip SETUP_CMD if true
|
||||
if [ "${WORKFLOW_WORKER}" == "true" ]; then
|
||||
echo "WORKFLOW_WORKER is set to true. Running worker process."
|
||||
npm run worker:prod
|
||||
else
|
||||
# Determine setup command based on the presence of ./server/dist
|
||||
if [ -d "./server/dist" ]; then
|
||||
SETUP_CMD='npm run db:setup:prod'
|
||||
else
|
||||
SETUP_CMD='npm run db:setup'
|
||||
fi
|
||||
fi
|
||||
|
||||
# Wait for PostgreSQL connection
|
||||
if [ -z "$DATABASE_URL" ]; then
|
||||
./server/scripts/wait-for-it.sh $PG_HOST:${PG_PORT:-5432} --strict --timeout=300 -- echo "PostgreSQL is up"
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ COPY ./package.json ./package.json
|
|||
COPY ./plugins/package.json ./plugins/package-lock.json ./plugins/
|
||||
RUN npm --prefix plugins ci --omit=dev
|
||||
COPY ./plugins/ ./plugins/
|
||||
RUN NODE_ENV=production npm --prefix plugins run build
|
||||
RUN npm --prefix plugins prune --omit=dev
|
||||
RUN NODE_ENV=production npm --prefix plugins run build && npm --prefix plugins prune --omit=dev
|
||||
|
||||
ENV TOOLJET_EDITION=ee
|
||||
|
||||
|
|
@ -52,14 +51,12 @@ ENV TOOLJET_EDITION=ee
|
|||
COPY ./server/package.json ./server/package-lock.json ./server/
|
||||
RUN npm --prefix server ci --omit=dev
|
||||
COPY ./server/ ./server/
|
||||
RUN npm install -g @nestjs/cli
|
||||
RUN npm install -g copyfiles
|
||||
RUN npm --prefix server run build
|
||||
RUN npm prune --production --prefix server
|
||||
RUN npm install -g @nestjs/cli && npm install -g copyfiles
|
||||
RUN npm --prefix server run build && npm prune --production --prefix server
|
||||
|
||||
# Install dependencies for PostgREST, curl, unzip, etc.
|
||||
# Install dependencies for PostgREST, curl, tar, etc.
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl ca-certificates unzip tar \
|
||||
curl ca-certificates tar \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV POSTGREST_VERSION=v12.2.0
|
||||
|
|
@ -81,7 +78,6 @@ RUN apt-get update && \
|
|||
ca-certificates \
|
||||
xz-utils \
|
||||
tar \
|
||||
zip \
|
||||
postgresql-client \
|
||||
redis \
|
||||
libaio1 \
|
||||
|
|
|
|||
|
|
@ -138,6 +138,15 @@ export const chartConfig = {
|
|||
displayName: 'Background color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border color',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
},
|
||||
accordian: 'container',
|
||||
},
|
||||
padding: {
|
||||
type: 'code',
|
||||
displayName: 'Padding',
|
||||
|
|
@ -233,6 +242,7 @@ export const chartConfig = {
|
|||
borderRadius: { value: '{{4}}' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
borderColor: { value: 'var(--cc-default-border)' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { isEqual } from 'lodash';
|
|||
import { deepClone } from '@/_helpers/utilities/utils.helpers';
|
||||
import useStore from '@/AppBuilder/_stores/store';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { getCssVarValue } from './utils';
|
||||
import { getCssVarValue, getModifiedColor } from './utils';
|
||||
|
||||
var tinycolor = require('tinycolor2');
|
||||
|
||||
|
|
@ -33,11 +33,11 @@ export const Chart = function Chart({
|
|||
return '#fff';
|
||||
};
|
||||
|
||||
const { padding, visibility, disabledState, boxShadow, backgroundColor, borderRadius } = styles;
|
||||
const { padding, visibility, disabledState, boxShadow, backgroundColor, borderRadius, borderColor } = styles;
|
||||
const { title, markerColor, showGridLines, type, data, jsonDescription, plotFromJson, showAxes, barmode } =
|
||||
properties;
|
||||
|
||||
const modifiedBackgroundColor = getCssVarValue(document.documentElement, backgroundColor);
|
||||
const modifiedBackgroundColor = getModifiedColor(backgroundColor, 0);
|
||||
const modifiedMarkerColor = getCssVarValue(document.documentElement, markerColor);
|
||||
const modifiedGridLines = getCssVarValue(document.documentElement, 'var(--cc-weak-border)');
|
||||
const modifiedTextColor = getCssVarValue(document.documentElement, 'var(--cc-primary-text)');
|
||||
|
|
@ -55,7 +55,8 @@ export const Chart = function Chart({
|
|||
width: width - 4,
|
||||
height,
|
||||
display: visibility ? '' : 'none',
|
||||
background: darkMode ? '#1f2936' : 'white',
|
||||
// background: darkMode ? '#1f2936' : 'white',
|
||||
border: `1px solid ${borderColor}`,
|
||||
boxShadow,
|
||||
borderRadius,
|
||||
};
|
||||
|
|
@ -82,6 +83,7 @@ export const Chart = function Chart({
|
|||
? '#1f2936'
|
||||
: '#fff'
|
||||
: modifiedBackgroundColor;
|
||||
|
||||
const fontColor = getColor(updatedBgColor);
|
||||
|
||||
const chartTitle = plotFromJson ? chartLayout?.title ?? title : title;
|
||||
|
|
@ -105,8 +107,8 @@ export const Chart = function Chart({
|
|||
}, [JSON.stringify(chartLayout, chartTitle)]);
|
||||
|
||||
const layout = {
|
||||
width: width - 4,
|
||||
height,
|
||||
width: width - 6,
|
||||
height: height - 4,
|
||||
plot_bgcolor: updatedBgColor,
|
||||
paper_bgcolor: updatedBgColor,
|
||||
title: {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 80f2e4cab88aa586e9b8a731f8643bcc0cef52e7
|
||||
Subproject commit cc864000dd03cc345e53ae9fc43821d3174f4c64
|
||||
|
|
@ -53,6 +53,7 @@ import { SampleDBScheduler } from '@modules/data-sources/schedulers/sample-db.sc
|
|||
import { SessionScheduler } from '@modules/session/scheduler';
|
||||
import { AuditLogsClearScheduler } from '@modules/audit-logs/scheduler';
|
||||
import { ModulesModule } from '@modules/modules/module';
|
||||
import { EmailListenerModule } from '@modules/email-listener/module';
|
||||
export class AppModule implements OnModuleInit {
|
||||
static async register(configs: { IS_GET_CONTEXT: boolean }): Promise<DynamicModule> {
|
||||
// Load static and dynamic modules
|
||||
|
|
@ -113,6 +114,7 @@ export class AppModule implements OnModuleInit {
|
|||
await AppGitModule.register(configs),
|
||||
await CrmModule.register(configs),
|
||||
await OrganizationPaymentModule.register(configs),
|
||||
await EmailListenerModule.register(configs),
|
||||
];
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -138,6 +138,15 @@ export const chartConfig = {
|
|||
displayName: 'Background color',
|
||||
validation: { schema: { type: 'string' }, defaultValue: 'var(--cc-surface1-surface)' },
|
||||
},
|
||||
borderColor: {
|
||||
type: 'colorSwatches',
|
||||
displayName: 'Border color',
|
||||
validation: {
|
||||
schema: { type: 'string' },
|
||||
defaultValue: 'var(--cc-default-border)',
|
||||
},
|
||||
accordian: 'container',
|
||||
},
|
||||
padding: {
|
||||
type: 'code',
|
||||
displayName: 'Padding',
|
||||
|
|
@ -233,6 +242,7 @@ export const chartConfig = {
|
|||
borderRadius: { value: '{{4}}' },
|
||||
visibility: { value: '{{true}}' },
|
||||
disabledState: { value: '{{false}}' },
|
||||
borderColor: { value: 'var(--cc-default-border)' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { Logger } from 'nestjs-pino';
|
||||
import { EmailEventPayload } from './constants';
|
||||
import { EmailEventPayload, EMAIL_EVENTS } from '@modules/email/constants';
|
||||
import { EmailService } from '@modules/email/service';
|
||||
import { EMAIL_EVENTS } from './constants';
|
||||
|
||||
@Injectable()
|
||||
export class EmailListener {
|
||||
|
|
@ -15,7 +14,6 @@ export class EmailListener {
|
|||
@OnEvent('emailEvent')
|
||||
async handleEmailEvent(eventData: EmailEventPayload) {
|
||||
const { type, payload } = eventData;
|
||||
|
||||
try {
|
||||
switch (type) {
|
||||
case EMAIL_EVENTS.SEND_WELCOME_EMAIL:
|
||||
17
server/src/modules/email-listener/module.ts
Normal file
17
server/src/modules/email-listener/module.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { DynamicModule } from '@nestjs/common';
|
||||
import { SubModule } from '@modules/app/sub-module';
|
||||
import { EmailModule } from '@modules/email/module';
|
||||
import { getImportPath } from '@modules/app/constants';
|
||||
|
||||
export class EmailListenerModule extends SubModule {
|
||||
static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise<DynamicModule> {
|
||||
const importPath = await getImportPath(configs?.IS_GET_CONTEXT);
|
||||
const { EmailListener } = await import(`${importPath}/email-listener/listener`);
|
||||
return {
|
||||
module: EmailListenerModule,
|
||||
imports: [await EmailModule.register(configs)],
|
||||
providers: [EmailListener],
|
||||
exports: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ export class EmailModule extends SubModule {
|
|||
const importPath = await getImportPath(configs?.IS_GET_CONTEXT);
|
||||
const { EmailService } = await import(`${importPath}/email/service`);
|
||||
const { EmailUtilService } = await import(`${importPath}/email/util.service`);
|
||||
const { EmailListener } = await import(`${importPath}/email/listener`);
|
||||
return {
|
||||
module: EmailModule,
|
||||
imports: [
|
||||
|
|
@ -18,8 +17,8 @@ export class EmailModule extends SubModule {
|
|||
await DataSourcesModule.register(configs),
|
||||
await SMTPModule.register(configs),
|
||||
],
|
||||
providers: [EmailService, EmailListener, EmailUtilService],
|
||||
exports: [EmailListener, EmailUtilService],
|
||||
providers: [EmailService, EmailUtilService],
|
||||
exports: [EmailUtilService, EmailService],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import {
|
|||
} from '@modules/email/dto';
|
||||
import { EmailUtilService } from './util.service';
|
||||
import { IEmailService } from './interfaces/IService';
|
||||
import { INSTANCE_SYSTEM_SETTINGS } from '@modules/instance-settings/constants';
|
||||
import { WhiteLabellingUtilService } from '@modules/white-labelling/util.service';
|
||||
|
||||
handlebars.registerHelper('capitalize', function (value) {
|
||||
|
|
@ -29,15 +28,6 @@ export class EmailService implements IEmailService {
|
|||
protected WHITE_LABEL_TEXT;
|
||||
protected WHITE_LABEL_LOGO;
|
||||
protected SUB_PATH;
|
||||
protected SMTP: {
|
||||
[INSTANCE_SYSTEM_SETTINGS.SMTP_ENABLED]: boolean;
|
||||
[INSTANCE_SYSTEM_SETTINGS.SMTP_DOMAIN]: string;
|
||||
[INSTANCE_SYSTEM_SETTINGS.SMTP_PORT]: string;
|
||||
[INSTANCE_SYSTEM_SETTINGS.SMTP_USERNAME]: string;
|
||||
[INSTANCE_SYSTEM_SETTINGS.SMTP_PASSWORD]: string;
|
||||
[INSTANCE_SYSTEM_SETTINGS.SMTP_FROM_EMAIL]: string;
|
||||
[INSTANCE_SYSTEM_SETTINGS.SMTP_ENV_CONFIGURED]: boolean;
|
||||
};
|
||||
protected defaultWhiteLabelState: boolean;
|
||||
|
||||
constructor(
|
||||
|
|
@ -63,14 +53,13 @@ export class EmailService implements IEmailService {
|
|||
|
||||
async init(organizationId?: string | null) {
|
||||
const whiteLabelSettings = await this.emailUtilService.retrieveWhiteLabelSettings(null);
|
||||
this.SMTP = await this.emailUtilService.retrieveSmtpSettings();
|
||||
this.WHITE_LABEL_TEXT = whiteLabelSettings?.white_label_text;
|
||||
this.WHITE_LABEL_LOGO = whiteLabelSettings?.white_label_logo;
|
||||
this.defaultWhiteLabelState = whiteLabelSettings?.default;
|
||||
}
|
||||
|
||||
protected compileTemplate(templatePath: string, templateData: object) {
|
||||
this.emailUtilService.compileTemplate(templatePath, templateData);
|
||||
return this.emailUtilService.compileTemplate(templatePath, templateData);
|
||||
}
|
||||
|
||||
protected stripTrailingSlash(hostname: string) {
|
||||
|
|
@ -88,6 +77,7 @@ export class EmailService implements IEmailService {
|
|||
redirectTo,
|
||||
} = payload;
|
||||
await this.init(organizationId);
|
||||
await this.emailUtilService.init(organizationId);
|
||||
const isOrgInvite = organizationInvitationToken && sender && organizationName;
|
||||
const inviteUrl = generateInviteURL(invitationtoken, organizationInvitationToken, organizationId, null, redirectTo);
|
||||
const subject = isOrgInvite ? `Welcome to ${organizationName || 'ToolJet'}` : 'Set up your account!';
|
||||
|
|
|
|||
|
|
@ -36,7 +36,11 @@ export class EmailUtilService implements IEmailUtilService {
|
|||
constructor(
|
||||
protected readonly whiteLabellingUtilService: WhiteLabellingUtilService,
|
||||
protected readonly smtpUtilService: SMTPUtilService
|
||||
) {}
|
||||
) {
|
||||
this.TOOLJET_HOST = this.stripTrailingSlash(process.env.TOOLJET_HOST);
|
||||
this.SUB_PATH = process.env.SUB_PATH;
|
||||
this.NODE_ENV = process.env.NODE_ENV || 'development';
|
||||
}
|
||||
|
||||
async retrieveWhiteLabelSettings(organizationId?: string | null): Promise<any> {
|
||||
const whiteLabelSetting = await this.whiteLabellingUtilService.getProcessedSettings(organizationId);
|
||||
|
|
@ -253,4 +257,14 @@ export class EmailUtilService implements IEmailUtilService {
|
|||
whiteLabelLogo: DEFAULT_WHITE_LABELLING_SETTINGS.white_label_logo,
|
||||
});
|
||||
}
|
||||
protected stripTrailingSlash(hostname: string) {
|
||||
return hostname?.endsWith('/') ? hostname.slice(0, -1) : hostname;
|
||||
}
|
||||
async init(organizationId?: string | null) {
|
||||
const whiteLabelSettings = await this.retrieveWhiteLabelSettings(null);
|
||||
this.SMTP = await this.retrieveSmtpSettings();
|
||||
this.WHITE_LABEL_TEXT = whiteLabelSettings?.white_label_text;
|
||||
this.WHITE_LABEL_LOGO = whiteLabelSettings?.white_label_logo;
|
||||
this.defaultWhiteLabelState = whiteLabelSettings?.default;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,6 +274,29 @@ export class LicenseCountsService implements ILicenseCountsService {
|
|||
manager
|
||||
);
|
||||
}
|
||||
async getUserIdWithEndUserRole(manager: EntityManager): Promise<string[]> {
|
||||
const statusList = [WORKSPACE_USER_STATUS.INVITED, WORKSPACE_USER_STATUS.ACTIVE];
|
||||
|
||||
const users = await manager.find(User, {
|
||||
select: ['id'],
|
||||
where: {
|
||||
status: Not(USER_STATUS.ARCHIVED),
|
||||
organizationUsers: {
|
||||
status: In(statusList),
|
||||
},
|
||||
userPermissions: {
|
||||
name: USER_ROLE.END_USER,
|
||||
organization: {
|
||||
status: WORKSPACE_STATUS.ACTIVE,
|
||||
},
|
||||
},
|
||||
},
|
||||
relations: ['organizationUsers', 'userPermissions', 'userPermissions.organization'],
|
||||
});
|
||||
|
||||
// Extract unique user IDs
|
||||
return [...new Set(users.map((user) => user.id))];
|
||||
}
|
||||
|
||||
async fetchTotalAppCount(organizationId: string, manager: EntityManager): Promise<number> {
|
||||
if (getTooljetEdition() !== TOOLJET_EDITIONS.Cloud) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue