Merge branch 'main' into fix/appbuilder-03

This commit is contained in:
johnsoncherian 2025-07-11 10:37:37 +05:30
commit 8133199d58
15 changed files with 75 additions and 38 deletions

View file

@ -21,7 +21,7 @@ jobs:
if: "contains(github.event.release.tag_name, '-ce-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/lts-3.6
ref: refs/heads/lts-3.16
# Create Docker Buildx builder with platform configuration
- name: Set up Docker Buildx
@ -108,7 +108,7 @@ jobs:
if: "contains(github.event.release.tag_name, '-ee-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/lts-3.6
ref: refs/heads/lts-3.16
# Create Docker Buildx builder with platform configuration
- name: Set up Docker Buildx
@ -155,7 +155,7 @@ jobs:
context: .
build-args: |
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
BRANCH_NAME=lts-3.6
BRANCH_NAME=lts-3.16
file: docker/ee/ee-production.Dockerfile
push: true
tags: tooljet/tooljet-ee:${{ github.event.release.tag_name }},tooljet/tooljet-ee:ee-lts-latest,tooljet/tooljet:ee-lts-latest,tooljet/tooljet:${{ github.event.release.tag_name }}
@ -185,7 +185,7 @@ jobs:
if: "contains(github.event.release.tag_name, '-cloud-lts')"
uses: actions/checkout@v2
with:
ref: refs/heads/lts-3.6
ref: refs/heads/lts-3.16
# Create Docker Buildx builder with platform configuration
- name: Set up Docker Buildx
@ -215,7 +215,7 @@ jobs:
context: .
build-args: |
CUSTOM_GITHUB_TOKEN=${{ secrets.CUSTOM_GITHUB_TOKEN }}
BRANCH_NAME=lts-3.6
BRANCH_NAME=lts-3.16
file: docker/cloud/cloud-server.Dockerfile
push: true
tags: tooljet/saas:${{ github.event.release.tag_name }}
@ -247,11 +247,11 @@ jobs:
with:
ref: refs/heads/main
- name: Checkout code to lts-3.0
- name: Checkout code to lts-3.16
if: contains(github.event.release.tag_name, '-ee-lts')
uses: actions/checkout@v2
with:
ref: refs/heads/lts-3.0
ref: refs/heads/lts-3.16
# Create Docker Buildx builder with platform configuration
- name: Set up Docker Buildx

View file

@ -16,11 +16,11 @@ jobs:
name: packer-ee
steps:
- name: Checkout code to lts-3.6 branch
- name: Checkout code to lts-3.16 branch
if: contains(github.event.release.tag_name, '-ee-lts')
uses: actions/checkout@v2
with:
ref: refs/heads/lts-3.6
ref: refs/heads/lts-3.16
- name: Setting tag
if: "${{ github.event.inputs.version != '' }}"

View file

@ -8,8 +8,8 @@
"typescript",
"typescriptreact"
],
"eslint.format.enable": true,
"editor.formatOnSave": true,
"eslint.format.enable": false,
"editor.formatOnSave": false,
"json.schemas": [
{
"fileMatch": [

@ -1 +1 @@
Subproject commit 245477ce5361e7ce2ade3056cb0c17a78a8fc6ec
Subproject commit 35fb9f47811a315c9ab8f3daa1a71cd804ba1215

View file

@ -34,6 +34,7 @@ const initialState = {
showDeleteConfirmation: false,
renamingQueryId: null,
deletingQueryId: null,
asyncQueryRuns: [],
};
export const createQueryPanelSlice = (set, get) => ({

View file

@ -94,6 +94,11 @@ export const AppMenu = function AppMenu({
<Field text={appType === 'module' ? 'Export module' : 'Export app'} onClick={exportApp} />
</>
)}
{canUpdateApp && canCreateApp && appType === 'workflow' && (
<>
<Field text={'Export workflow'} onClick={exportApp} />
</>
)}
{canDeleteApp && (
<Field
text={

View file

@ -478,7 +478,7 @@ class HomePageComponent extends React.Component {
let installedPluginsInfo = [];
try {
if (this.state.dependentPlugins.length) {
({ installedPluginsInfo =[] } = await pluginsService.installDependentPlugins(
({ installedPluginsInfo = [] } = await pluginsService.installDependentPlugins(
this.state.dependentPlugins,
true
));
@ -486,7 +486,8 @@ class HomePageComponent extends React.Component {
if (importJSON.app[0].definition.appV2.type !== this.props.appType) {
toast.error(
`${this.props.appType === 'module' ? 'App' : 'Module'} could not be imported in ${this.props.appType === 'module' ? 'modules' : 'apps'
`${this.props.appType === 'module' ? 'App' : 'Module'} could not be imported in ${
this.props.appType === 'module' ? 'modules' : 'apps'
} section. Switch to ${this.props.appType === 'module' ? 'apps' : 'modules'} section and try again.`,
{ style: { maxWidth: '425px' } }
);
@ -495,7 +496,7 @@ class HomePageComponent extends React.Component {
}
const data = await appsService.importResource(requestBody, this.props.appType);
toast.success(`${this.props.appType === 'module' ? 'Module' : 'App'} imported successfully.`);
toast.success(`${this.getAppType()} imported successfully.`);
this.setState({ isImportingApp: false });
if (!isEmpty(data.imports.app)) {
@ -1154,13 +1155,14 @@ class HomePageComponent extends React.Component {
closeModal: () => this.setState({ showImportAppModal: false }),
processApp: this.importFile,
show: this.openImportAppModal,
title: 'Import app',
actionButton: 'Import app',
title: `Import ${this.getAppType().toLocaleLowerCase()}`,
actionButton: `Import ${this.getAppType().toLocaleLowerCase()}`,
actionLoadingButton: 'Importing',
fileContent: fileContent,
selectedAppName: fileName,
dependentPluginsDetail: dependentPluginsDetail,
dependentPlugins: dependentPlugins,
appType: this.props.appType,
},
template: {
modalType: 'template',
@ -1224,8 +1226,9 @@ class HomePageComponent extends React.Component {
<div className="groups-list">
<div
className={`border rounded text-sm container ${missingGroupsExpanded ? 'max-h-48 overflow-y-auto' : ''
}`}
className={`border rounded text-sm container ${
missingGroupsExpanded ? 'max-h-48 overflow-y-auto' : ''
}`}
>
<div style={{ color: 'var(--text-placeholder)' }} className="tj-text-xsm font-weight-500">
User groups
@ -1301,8 +1304,8 @@ class HomePageComponent extends React.Component {
this.props.appType === 'workflow'
? 'homePage.deleteWorkflowAndData'
: this.props.appType === 'front-end'
? 'homePage.deleteAppAndData'
: deleteModuleText,
? 'homePage.deleteAppAndData'
: deleteModuleText,
{
appName: appToBeDeleted?.name,
}
@ -1567,10 +1570,11 @@ class HomePageComponent extends React.Component {
{this.props.appType === 'module'
? 'Create new module'
: this.props.t(
`${this.props.appType === 'workflow' ? 'workflowsDashboard' : 'homePage'
}.header.createNewApplication`,
'Create new app'
)}
`${
this.props.appType === 'workflow' ? 'workflowsDashboard' : 'homePage'
}.header.createNewApplication`,
'Create new app'
)}
</>
</Button>
<Dropdown.Toggle
@ -1631,8 +1635,8 @@ class HomePageComponent extends React.Component {
classes="mb-3 small"
limits={
workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total ||
100 > workflowInstanceLevelLimit.percentage >= 90 ||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1
100 > workflowInstanceLevelLimit.percentage >= 90 ||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1
? workflowInstanceLevelLimit
: workflowWorkspaceLevelLimit
}
@ -1726,8 +1730,8 @@ class HomePageComponent extends React.Component {
appType={this.props.appType}
workflowsLimit={
workflowInstanceLevelLimit.current >= workflowInstanceLevelLimit.total ||
100 > workflowInstanceLevelLimit.percentage >= 90 ||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1
100 > workflowInstanceLevelLimit.percentage >= 90 ||
workflowInstanceLevelLimit.current === workflowInstanceLevelLimit.total - 1
? workflowInstanceLevelLimit
: workflowWorkspaceLevelLimit
}

View file

@ -17,7 +17,7 @@ const BaseImportAppMenu = ({
const { t } = useTranslation();
return (
<Dropdown.Menu className="import-lg-position new-app-dropdown">
{appType !== 'wzorkflow' && appType !== 'module' && (
{appType !== 'workflow' && appType !== 'module' && (
<Dropdown.Item
className="homepage-dropdown-style tj-text tj-text-xsm"
onClick={showTemplateLibraryModal}

@ -1 +1 @@
Subproject commit f07d4f66de3e25fe5b1dc7c6d3f1226ad00a1f0c
Subproject commit 0fbde4b3030aa2117b7b8b024d11c5e175e4302a

View file

@ -32,6 +32,7 @@ export function defineWorkflowAbility(
FEATURE_KEY.RELEASE,
FEATURE_KEY.VALIDATE_PRIVATE_APP_ACCESS,
FEATURE_KEY.VALIDATE_RELEASED_APP_ACCESS,
FEATURE_KEY.UPDATE_ICON,
],
App
);
@ -56,6 +57,7 @@ export function defineWorkflowAbility(
FEATURE_KEY.RELEASE,
FEATURE_KEY.VALIDATE_PRIVATE_APP_ACCESS,
FEATURE_KEY.VALIDATE_RELEASED_APP_ACCESS,
FEATURE_KEY.UPDATE_ICON,
],
App
);

View file

@ -52,6 +52,11 @@ export class AppsModule extends SubModule {
'services/page.util.service',
]);
const { AppsActionsListener, TemporalService } = await this.getProviders(configs, 'workflows', [
'listeners/app-actions.listener',
'services/temporal.service',
]);
return {
module: AppsModule,
imports: [
@ -74,6 +79,8 @@ export class AppsModule extends SubModule {
VersionRepository,
AppsRepository,
AppGitRepository,
AppsActionsListener,
TemporalService,
PageService,
EventsService,
AppsUtilService,

View file

@ -42,6 +42,7 @@ import { AUDIT_LOGS_REQUEST_CONTEXT_KEY } from '@modules/app/constants';
import { MODULES } from '@modules/app/constants/modules';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { AppGitRepository } from '@modules/app-git/repository';
import { WorkflowSchedule } from '@entities/workflow_schedule.entity';
@Injectable()
export class AppsService implements IAppsService {
@ -181,7 +182,24 @@ export class AppsService implements IAppsService {
const { organizationId } = user;
const { id } = app;
await this.appRepository.delete({ id, organizationId });
await dbTransactionWrap(async (manager: EntityManager) => {
const schedules = await manager
.createQueryBuilder(WorkflowSchedule, 'workflowSchedule')
.innerJoinAndSelect('workflowSchedule.workflow', 'appVersion')
.where('appVersion.appId = :appId', { appId: id })
.getMany();
// Emit event with schedule IDs for temporal schedule cleanup
if (schedules.length > 0) {
const scheduleIds = schedules.map((schedule) => schedule.id);
this.eventEmitter.emit('app.deleted', {
appId: id,
scheduleIds: scheduleIds,
});
}
await manager.delete(App, { id, organizationId });
});
//APP_DELETE audit
RequestContext.setLocals(AUDIT_LOGS_REQUEST_CONTEXT_KEY, {

View file

@ -7,7 +7,7 @@ import { LicenseUserService } from '@modules/licensing/services/user.service';
import { RolesUtilService } from '@modules/roles/util.service';
import { OrganizationUser } from '../../entities/organization_user.entity';
import { generateNextNameAndSlug } from 'src/helpers/utils.helper';
const uuid = require('uuid');
import * as uuid from 'uuid';
import { Organization } from '../../entities/organization.entity';
import { EntityManager } from 'typeorm';
import {
@ -121,7 +121,7 @@ export class AuthUtilService implements IAuthUtilService {
try {
const signedJwt = this.sessionUtilService.verifyToken(token);
return signedJwt;
} catch (err) {
} catch {
return null;
}
}

View file

@ -98,8 +98,8 @@ export class UserRepository extends Repository<User> {
const existingUser = await manager.findOne(User, { where: { email: user.email } });
if (existingUser) {
Object.assign(existingUser, user);
return manager.update(User, { id: existingUser.id }, user);
await manager.update(User, { id: existingUser.id }, user);
return manager.findOne(User, { where: { id: existingUser.id } });
} else {
const newUser = manager.create(User, user);
return manager.save(User, newUser);

View file

@ -4,8 +4,8 @@ import { OnEvent } from '@nestjs/event-emitter';
@Injectable()
export class AppsActionsListener {
constructor() {}
@OnEvent('beforeAppDelete')
@OnEvent('app.deleted')
async handleAppDeletion(args: { appId: string }) {
throw new Error('Method not implemented');
console.log(`App with ID ${args.appId} has been deleted.`);
}
}