mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
* feat: enable version management panel for modules
Move VersionManagerDropdown and RightTopHeaderButtons outside the
isModuleEditor gate so module builders get the same version management
UI as apps — create drafts, save versions, promote, edit details,
and delete. BranchDropdown stays gated (git sync is Phase 2).
Refs: ToolJet/tj-ee#4925
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule for module version pinning
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — version dropdown design fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — compact dropdown styling
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: prevent deletion of module versions pinned by consuming apps
Query all ModuleViewer components to check if any app references the
target version via moduleVersionId. If in use, reject deletion with
a list of consuming app names.
Refs: ToolJet/tj-ee#4927
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — version selection fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: enable runtime resolution for pinned module versions
When a module component has a pinned versionId, use the version-specific
API (appVersionService.getAppVersionData) to load that version's definition
instead of always loading the module's current/latest version.
Also add versionId to useEffect deps so the module re-fetches when the
user changes the pinned version in the dropdown.
Refs: ToolJet/tj-ee#4926
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review findings — scoped deletion query, error handling
- Replace full table scan in checkModuleVersionInUse with scoped SQL
query using JSON extraction (properties::jsonb -> 'moduleVersionId')
instead of loading all ModuleViewer components into memory
- Add try-catch with user-friendly error message
- Update frontend/ee submodule with error logging and DRAFT fallback fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: module deletion guard, import version mapping, and error display
- Prevent deletion of modules referenced by consuming apps (checks
ModuleViewer components by moduleAppId)
- Fix import version ID remapping: map ALL version IDs instead of only
editingVersion, and match existing module versions by name
- Fix showViewerNavigation defaulting to true on import (|| → ??)
- Show actual API error message in delete toast instead of generic text
- Clean up error messages: remove em-dash, use multiline format
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: hide Configure Git button in module builder
Git sync for modules is Phase 2. Hide the LifecycleCTAButton when
in module editor context.
Refs: #15857
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: hide freeze banner in module builder to prevent canvas shift
The AppCanvasBanner renders a FreezeVersionInfo banner when a version
is saved (frozen). In the module builder, this banner pushed the canvas
down. Since git sync banners are not applicable to modules (Phase 2),
skip rendering entirely for module editors.
Refs: #15857
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — version dropdown loading state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — canvas padding fix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove hardcoded 'development' environment for modules
Modules now support environments, so remove the special case that
hardcoded the development environment for module viewer mode. Use
the same appEnvironmentService.getEnvironment call as apps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: freeze editor for promoted module versions
Remove the blanket `if (isModuleEditor) return false` from
getShouldFreeze(). Modules now have environments, so promoted/saved
versions should freeze the editor and query panel just like apps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — version lock banner for modules
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — latest version pre-selection
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — robust latest version sort
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: release gate blocks app release with unreleased modules
Check all ModuleViewer components in the app version being released.
If any pinned module version is not RELEASED, block with error listing
the unreleased modules.
Also updates frontend/ee submodule with env check and status badges.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — debugger integration for env mismatch
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: block app promotion when pinned modules not in target env
Add promote gate in promoteVersion() that checks all ModuleViewer
components. If any pinned module version hasn't been promoted to the
target environment, block with error listing the modules.
Also updates frontend/ee: simplified dropdown badges, removed
env mismatch placeholder (now prevented by this backend gate).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: show actual API error in release and promote toasts
Release button was showing "Oops, something went wrong" and promote
button was showing a generic retry message. Now both show the actual
backend error (e.g., module not released/promoted). Release errors
are also pushed to the app debugger.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use raw table names in release and promote gate queries
TypeORM innerJoin with entity classes generates incorrect SQL when
join conditions use ::text casts. Switch to raw table/column names
(app_versions, apps, app_environments) instead of entity references.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use lowercase aliases and correct enum in gate queries
- Use snake_case aliases (mod_ver, mod_app, mod_env) to avoid
PostgreSQL case-sensitivity issues with camelCase aliases
- Check for DRAFT status instead of RELEASED (RELEASED doesn't
exist in the DB version_status_enum)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: release gate checks current_version_id, errors in debugger
- Release gate now checks if pinned module version matches the
module's current_version_id (actual release mechanism), not just
DRAFT status
- Promote gate uses APP_TYPES.FRONT_END constant instead of raw string
- Both release and promote errors now show actual API message in toast
AND push to the app debugger
- Fixed inline ReleaseVersionButton (version panel) error handler
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: debugger log format and version dropdown design language
- Use type 'component' with description field for debugger logs
so the error message is visible in the debugger panel
- Update frontend/ee submodule: status dots in dropdown, draft
modules visible in component panel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update server/ee submodule — promote gate in EE override
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: move module guards from CE to EE only
Module-specific guards (deletion, release, promote) belong in EE
since modules are an EE-only feature. CE users who downgrade would
be blocked by stale module references they can't fix.
- Removed module deletion guard from CE apps/service.ts
- Removed release gate from CE apps/service.ts
- Removed dead promote gate from CE versions/service.ts
- All three guards now live in EE overrides only
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: format module names on separate lines in error messages
Each module name now appears on its own line in error toasts for
deletion, release, and promote gates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update frontend/ee submodule — Released badge in version dropdown
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update server/ee submodule — newline formatting in error messages
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: code review findings + design feedback
Review fixes:
- Guard checkModuleVersionInUse with app.type === 'module' to skip
unnecessary JSONB queries for non-module version deletions
- Exclude self-references in EE deletion guard
- Add DISTINCT to release gate query
- LEFT JOIN on environments in promote gate to catch NULL env IDs
Design feedback (Nechal):
- Remove status dots from version dropdown (clutter in small dropdown)
- Badge hugs the version name with tighter gap
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: code review fixes + module version audit log keys
PR review fixes:
- Move hooks above early return in LifecycleCTAButton (Rules of Hooks)
- Move UI state cleanup before debugger.log in error handlers
- Add missing setShowConfirmation(false) in modules ReleaseVersionButton
- Add fallback mapping for unmatched version IDs on module import
- Add Logger for checkModuleVersionInUse error logging
Audit log event names for module versioning:
- Add MODULE_VERSION_AUDIT_KEYS constants (CREATE/DELETE/SAVE/PROMOTE/RELEASE)
- Interceptor prefers service-set actionType over feature config
- Version/app services set module-specific audit keys when app.type === 'module'
- Add auditLogsKey for module CRUD features (MODULE_CREATE/DELETE/UPDATE)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: revert unrelated review changes + move audit keys to modules
- Revert LifecycleCTAButton hooks reorder (unrelated to this PR)
- Revert ReleaseVersionButton/PromoteConfirmationModal try-catch wrappers
- Move MODULE_VERSION_AUDIT_KEYS from versions/constants to modules/constants
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update server/ee submodule pointer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: skip git sync freeze for modules in version service
Modules are common across all branches — git sync freeze does not apply.
Adds app.type !== 'module' guard in CE prepareResponse.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: scalable error copy for module dependency gates
Frontend catch handlers now extract structured errors — toast shows
generic message, debugger description shows full module list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: read structured error fields correctly in catch handlers
Read rawError.error (not rawError.message) to match the { error, details }
shape from BadRequestException({ message: { error, details } }).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update server/ee submodule — error copy polish
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update server/ee submodule — freeze module after version save
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update server/ee submodule — widen module freeze check
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: module environment derivation, version switch crash, and delete toast
- Derive module environment from parent app's store instead of static
moduleEnvironmentId property. Ensures constants/secrets/queries
resolve from the correct environment per the compatibility matrix.
- Remove moduleEnvironmentId from all write/read/import-export paths.
Existing DB values are inert and harmless.
- Add key={moduleVersionId} to <Viewer> to force clean re-mount on
version switch, preventing stale state crash (empty canvas).
- Add stale-request cancellation guard in useAppData to prevent
unmounted component's async callback from overwriting new state.
- Fix delete-version toast: "Cannot delete only version of module"
instead of "app" when deleting the last module version.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: block app version save when using draft module versions
Saving an app version is now blocked if any ModuleViewer components
reference draft module versions. The draft module is still editable,
so saving the app would break the contract that saved = immutable.
- Added checkDraftModulesInApp() in CE util.service.ts (mirrors
checkModuleVersionInUse pattern)
- Called from update() before DRAFT→PUBLISHED status transition
- Structured error format: toast shows message, debugger shows
full module list
- Module saving itself is unaffected (guard checks app.type)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make checkDraftModulesInApp public (TS2445)
Called from VersionService.update() which is outside the class.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: data migration to promote and release existing module versions
Modules now inherit the parent app's environment for constants and
data sources. Existing modules had current_environment_id pointing
to Development, which would break apps viewing them in Staging or
Production.
This migration promotes the latest version of each module to the
production environment and sets it as released - mirroring the
workflow versioning migration pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: modules in public apps - cache-first load + constantsResp guard
Public app viewers are unauthenticated, so module data fetches via
getAppVersionData (JwtAuthGuard) fail with 401. Two fixes:
1. Try getModuleDefinition() cache before API call. Parent app's
public response includes module definitions, so the cache hit
avoids the authenticated endpoint entirely.
2. Guard constantsResp against undefined. When the environment
fetch fails (401 for public apps), constantsResp was undefined
causing a TypeError crash on extractEnvironmentConstantsFromConstantsList.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: restrict cache-first module loading to public access only
Cache-first was overly broad - could serve stale definitions in
authenticated editor previews. Now gated on isPublicAccess so
version-pinned API calls are preserved for authenticated flows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: modules with data queries crash in public/released apps
Two issues (ported from PR #15874):
1. Deep-clone cached module definitions before resolving. Zustand/Immer
returns frozen objects, but normalizeQueryTransformationOptions
mutates query options in-place causing TypeError on frozen objects.
Only manifests when modules have data queries.
2. Add id field to CE getBySlug module response. setModuleDefinition
stores by module.id - without it, getModuleDefinition(appId) cannot
find the cached definition. EE already had this (line 694).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: allow module query execution in public apps
QueryAuthGuard.findByDataQuery returns the MODULE app (query owner),
not the parent app. Modules aren't marked is_public, so the guard
rejected unauthenticated requests with "Authentication is required."
Added isModuleInPublicApp() check: when the query's owning app is a
module and not public itself, check if it's used in the released
version of any public app. Only checks current_version_id (released)
to prevent unauthorized access via unpublished app versions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Revert "fix: allow module query execution in public apps"
This reverts commit 7917eba47b.
* fix: modules should not inherit git branching locked state
- Backend: skip git sync freeze for modules in CE getOne, add
version-status freeze for non-draft module versions
- Frontend: make getShouldFreeze accept and use isModuleEditor param
(was silently ignored, affecting 20+ UI disable points)
* chore: update submodule pointers
* fix: getShouldFreeze module bypass must check version status not just released
The previous module bypass only checked isVersionReleased, missing
PUBLISHED (saved/promoted) versions. Check selectedVersion.status
directly since isEditorFreezed is shared state contaminated by the
parent app's git sync freeze.
* fix: handle nullable version status in module freeze check
Status column is nullable — null/undefined should be treated as DRAFT
(editable), not frozen. Use AppVersionStatus enum in CE backend.
* chore: update submodule pointers
* chore: update submodule pointers
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
65 lines
2 KiB
TypeScript
65 lines
2 KiB
TypeScript
import { MigrationInterface, QueryRunner } from 'typeorm';
|
|
import { Organization } from '@entities/organization.entity';
|
|
import { App } from '@entities/app.entity';
|
|
import { AppVersion, AppVersionStatus } from '@entities/app_version.entity';
|
|
import { MigrationProgress } from '@helpers/migration.helper';
|
|
import { APP_TYPES } from '@modules/apps/constants';
|
|
|
|
export class PromoteAndReleaseExistingModuleVersions1776419051000 implements MigrationInterface {
|
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
|
const manager = queryRunner.manager;
|
|
|
|
const organizations = await manager.find(Organization, {
|
|
select: ['id'],
|
|
relations: ['appEnvironments'],
|
|
});
|
|
|
|
const migrationProgress = new MigrationProgress(
|
|
'PromoteAndReleaseExistingModuleVersions',
|
|
organizations.length
|
|
);
|
|
|
|
for (const organization of organizations) {
|
|
const productionEnvironment = organization.appEnvironments.find((env) => env.isDefault);
|
|
|
|
if (!productionEnvironment) {
|
|
migrationProgress.show();
|
|
continue;
|
|
}
|
|
|
|
const moduleApps = await manager.find(App, {
|
|
where: { organizationId: organization.id, type: APP_TYPES.MODULE },
|
|
select: ['id', 'currentVersionId'],
|
|
});
|
|
|
|
for (const app of moduleApps) {
|
|
const versions = await manager.find(AppVersion, {
|
|
where: { appId: app.id },
|
|
order: { createdAt: 'DESC' },
|
|
select: ['id', 'createdAt'],
|
|
});
|
|
|
|
if (!versions.length) continue;
|
|
|
|
const latestVersion = versions[0];
|
|
|
|
await manager.update(
|
|
AppVersion,
|
|
{ id: latestVersion.id },
|
|
{
|
|
currentEnvironmentId: productionEnvironment.id,
|
|
status: AppVersionStatus.PUBLISHED,
|
|
}
|
|
);
|
|
|
|
await manager.update(App, { id: app.id }, { currentVersionId: latestVersion.id });
|
|
|
|
console.log(`Released module ${app.id} → version ${latestVersion.id}`);
|
|
}
|
|
|
|
migrationProgress.show();
|
|
}
|
|
}
|
|
|
|
public async down(queryRunner: QueryRunner): Promise<void> {}
|
|
}
|