mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-05 22:38:48 +00:00
Merge pull request #13318 from ToolJet/release/workflows-fixes
### Changelog #### Enhancements * Added optional chaining for `renderCopilot` function call as it's not guaranteed to be present * Added export option for workflows in AppMenu #### Fixes * Fixed scroll issue for large set of logs in response * Removed 'Choose from Template' option from import menu * Fixed loop icon issue in logs and import workflow modal text issues * Initialized `asyncQueryRuns` in the state to avoid accessing undefined values * Workflow schedule cleanup * Updated subproject commit reference * Fixed: update subproject commit reference #### Chores * Updated subproject commits for frontend and server * Updated subproject commit reference in `server/ee` * Updated base repo for submodule commit
This commit is contained in:
commit
d5c7d6d695
10 changed files with 60 additions and 23 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 113d2ec5525571afd0a08187552a5b0d0979ecc3
|
||||
Subproject commit 5ebcf5ccda1d11cb73e77b9a9bf71c16e1404c7b
|
||||
|
|
@ -34,6 +34,7 @@ const initialState = {
|
|||
showDeleteConfirmation: false,
|
||||
renamingQueryId: null,
|
||||
deletingQueryId: null,
|
||||
asyncQueryRuns: [],
|
||||
};
|
||||
|
||||
export const createQueryPanelSlice = (set, get) => ({
|
||||
|
|
|
|||
|
|
@ -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={
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 80886c9d5e30e738e9b7bb2e9acd42d20fcbf810
|
||||
Subproject commit 2f0948893fdea517479ba3cc2da421a06dff6a64
|
||||
|
|
@ -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
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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, {
|
||||
|
|
|
|||
|
|
@ -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.`);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue