diff --git a/frontend/src/Editor/QueryManager/Components/DataSourceSelect.jsx b/frontend/src/Editor/QueryManager/Components/DataSourceSelect.jsx
index 7e8865cdfe..d1afd378f4 100644
--- a/frontend/src/Editor/QueryManager/Components/DataSourceSelect.jsx
+++ b/frontend/src/Editor/QueryManager/Components/DataSourceSelect.jsx
@@ -7,7 +7,6 @@ import { getWorkspaceId, decodeEntities } from '@/_helpers/utils';
import { ButtonSolid } from '@/_ui/AppButton/AppButton';
import { useDataSources, useGlobalDataSources, useSampleDataSource } from '@/_stores/dataSourcesStore';
import { useDataQueriesActions } from '@/_stores/dataQueriesStore';
-import { staticDataSources as staticDatasources } from '../constants';
import { useQueryPanelActions } from '@/_stores/queryPanelStore';
import Search from '@/_ui/Icon/solidIcons/Search';
import { Tooltip } from 'react-tooltip';
@@ -16,7 +15,7 @@ import { canCreateDataSource } from '@/_helpers';
import './../queryManager.theme.scss';
import { DATA_SOURCE_TYPE } from '@/_helpers/constants';
-function DataSourceSelect({ isDisabled, selectRef, closePopup, workflowDataSources, onNewNode, defaultDataSources }) {
+function DataSourceSelect({ isDisabled, selectRef, closePopup, workflowDataSources, onNewNode, staticDataSources }) {
const dataSources = useDataSources();
const globalDataSources = useGlobalDataSources();
const sampleDataSource = useSampleDataSource();
@@ -33,11 +32,6 @@ function DataSourceSelect({ isDisabled, selectRef, closePopup, workflowDataSourc
closePopup();
};
- const workflowsEnabled = window.public_config?.ENABLE_WORKFLOWS_FEATURE == 'true';
- const staticDataSources = workflowsEnabled
- ? staticDatasources
- : staticDatasources.filter((ds) => ds?.kind !== 'workflows');
-
useEffect(() => {
const shouldAddSampleDataSource = !!sampleDataSource;
const allDataSources = [...dataSources, ...globalDataSources, shouldAddSampleDataSource && sampleDataSource].filter(
@@ -148,7 +142,7 @@ function DataSourceSelect({ isDisabled, selectRef, closePopup, workflowDataSourc
),
isDisabled: true,
- options: defaultDataSources?.map((source) => ({
+ options: staticDataSources?.map((source) => ({
label: (
{' '}
diff --git a/frontend/src/_helpers/constants.js b/frontend/src/_helpers/constants.js
index 1c3c3d48b6..79275fc6df 100644
--- a/frontend/src/_helpers/constants.js
+++ b/frontend/src/_helpers/constants.js
@@ -129,6 +129,7 @@ export const DATA_SOURCE_TYPE = {
LOCAL: 'local',
GLOBAL: 'global',
STATIC: 'static',
+ DEFAULT: 'default',
};
export const SAMPLE_DB_KIND = {
diff --git a/server/src/dto/app-version-update.dto.ts b/server/src/dto/app-version-update.dto.ts
index 6c7aadb71c..cc83273ba0 100644
--- a/server/src/dto/app-version-update.dto.ts
+++ b/server/src/dto/app-version-update.dto.ts
@@ -26,4 +26,17 @@ export class AppVersionUpdateDto {
@IsOptional()
pageSettings: any;
+
+ // Workflow related fields
+ @IsOptional()
+ @IsString()
+ @IsUUID()
+ currentEnvironmentId: string;
+
+ @IsOptional()
+ definition: any;
+
+ @IsOptional()
+ @IsBoolean()
+ is_user_switched_version: boolean;
}
diff --git a/server/src/modules/apps/dto/index.ts b/server/src/modules/apps/dto/index.ts
index 63d93bd9d3..532740273a 100644
--- a/server/src/modules/apps/dto/index.ts
+++ b/server/src/modules/apps/dto/index.ts
@@ -1,6 +1,7 @@
import { sanitizeInput } from '@helpers/utils.helper';
-import { IsString, IsOptional, IsNotEmpty, MaxLength, IsBoolean, IsUUID } from 'class-validator';
+import { IsString, IsOptional, IsNotEmpty, MaxLength, IsBoolean, IsUUID, IsEnum } from 'class-validator';
import { Exclude, Expose, Transform } from 'class-transformer';
+import { APP_TYPES } from '../constants';
export class AppCreateDto {
@IsNotEmpty()
@@ -12,6 +13,11 @@ export class AppCreateDto {
@IsString()
@MaxLength(200, { message: 'Maximum length has been reached.' })
icon?: string;
+
+ @IsNotEmpty()
+ @IsString()
+ @IsEnum(APP_TYPES, { message: 'Invalid app type.' })
+ type: string;
}
export class AppUpdateDto {
diff --git a/server/src/modules/apps/service.ts b/server/src/modules/apps/service.ts
index 7ad0ca351a..60c6f8bc15 100644
--- a/server/src/modules/apps/service.ts
+++ b/server/src/modules/apps/service.ts
@@ -60,9 +60,9 @@ export class AppsService implements IAppsService {
protected readonly aiUtilService: AiUtilService
) {}
async create(user: User, appCreateDto: AppCreateDto) {
- const { name, icon } = appCreateDto;
+ const { name, icon, type } = appCreateDto;
return await dbTransactionWrap(async (manager: EntityManager) => {
- const app = await this.appsUtilService.create(name, user, APP_TYPES.FRONT_END, manager);
+ const app = await this.appsUtilService.create(name, user, type, manager);
const appUpdateDto = new AppUpdateDto();
appUpdateDto.name = name;
diff --git a/server/src/modules/apps/util.service.ts b/server/src/modules/apps/util.service.ts
index 7be1609b32..36def10913 100644
--- a/server/src/modules/apps/util.service.ts
+++ b/server/src/modules/apps/util.service.ts
@@ -11,7 +11,7 @@ import {
NotAcceptableException,
NotFoundException,
} from '@nestjs/common';
-import { EntityManager, SelectQueryBuilder } from 'typeorm';
+import { EntityManager, MoreThan, SelectQueryBuilder } from 'typeorm';
import { v4 as uuidv4 } from 'uuid';
import { AppsRepository } from './repository';
import { AppVersion } from '@entities/app_version.entity';
@@ -36,6 +36,7 @@ import { AbilityService } from '@modules/ability/interfaces/IService';
import { DataSourcesRepository } from '@modules/data-sources/repository';
import { IAppsUtilService } from './interfaces/IUtilService';
import { DataSourcesUtilService } from '@modules/data-sources/util.service';
+import { AppVersionUpdateDto } from '@dto/app-version-update.dto';
@Injectable()
export class AppsUtilService implements IAppsUtilService {
@@ -281,6 +282,70 @@ export class AppsUtilService implements IAppsUtilService {
}, manager);
}
+ async updateWorflowVersion(version: AppVersion, body: AppVersionUpdateDto, app: App) {
+ const { name, currentEnvironmentId, definition } = body;
+ const { currentVersionId, organizationId } = app;
+ let currentEnvironment: AppEnvironment;
+
+ if (version.id === currentVersionId && !body?.is_user_switched_version)
+ throw new BadRequestException('You cannot update a released version');
+
+ if (currentEnvironmentId || definition) {
+ currentEnvironment = await AppEnvironment.findOne({
+ where: { id: version.currentEnvironmentId },
+ });
+ }
+
+ const editableParams = {};
+ if (name) {
+ //means user is trying to update the name
+ const versionNameExists = await this.versionRepository.findOne({
+ where: { name, appId: version.appId },
+ });
+
+ if (versionNameExists) {
+ throw new BadRequestException('Version name already exists.');
+ }
+ editableParams['name'] = name;
+ }
+
+ //check if the user is trying to promote the environment & raise an error if the currentEnvironmentId is not correct
+ if (currentEnvironmentId) {
+ if (!(await this.licenseTermsService.getLicenseTerms(LICENSE_FIELD.MULTI_ENVIRONMENT))) {
+ throw new BadRequestException('You do not have permissions to perform this action');
+ }
+
+ if (version.currentEnvironmentId !== currentEnvironmentId) {
+ throw new NotAcceptableException();
+ }
+ const nextEnvironment = await AppEnvironment.findOne({
+ select: ['id'],
+ where: {
+ priority: MoreThan(currentEnvironment.priority),
+ organizationId,
+ },
+ order: { priority: 'ASC' },
+ });
+ editableParams['currentEnvironmentId'] = nextEnvironment.id;
+ }
+
+ if (definition) {
+ const environments = await AppEnvironment.count({
+ where: {
+ organizationId,
+ },
+ });
+ if (environments > 1 && currentEnvironment.priority !== 1 && !body?.is_user_switched_version) {
+ throw new BadRequestException('You cannot update a promoted version');
+ }
+ editableParams['definition'] = definition;
+ }
+
+ editableParams['updatedAt'] = new Date();
+
+ return await this.versionRepository.update(version.id, editableParams);
+ }
+
protected async getEnvironmentOfVersion(versionId: string, manager: EntityManager): Promise
{
return manager
.createQueryBuilder(AppEnvironment, 'app_environments')
diff --git a/server/src/modules/data-queries/service.ts b/server/src/modules/data-queries/service.ts
index 874b3b0ee2..e8852da22d 100644
--- a/server/src/modules/data-queries/service.ts
+++ b/server/src/modules/data-queries/service.ts
@@ -191,11 +191,12 @@ export class DataQueriesService implements IDataQueriesService {
async changeQueryDataSource(user: User, queryId: string, dataSource: DataSource, newDataSourceId: string) {
return dbTransactionWrap(async (manager: EntityManager) => {
- const newDataSource = await this.dataSourceRepository.findOne({ where: { id: newDataSourceId } });
- if (dataSource.kind !== newDataSource.kind) {
- throw new BadRequestException();
- }
- return this.dataQueryRepository.updateOne(queryId, { dataSourceId: newDataSourceId }, manager);
+ const newDataSource = await this.dataSourceRepository.findOneOrFail({ where: { id: newDataSourceId } });
+ // FIXME: Disabling this check as workflows can change data source of a query with different kind
+ // if (dataSource.kind !== newDataSource.kind && dataSource) {
+ // throw new BadRequestException();
+ // }
+ return this.dataQueryRepository.updateOne(queryId, { dataSourceId: newDataSource.id }, manager);
// TODO: Audit logs
});
diff --git a/server/src/modules/versions/service.ts b/server/src/modules/versions/service.ts
index c4e263456f..e50b66b50b 100644
--- a/server/src/modules/versions/service.ts
+++ b/server/src/modules/versions/service.ts
@@ -175,6 +175,10 @@ export class VersionService implements IVersionService {
await this.versionsUtilService.updateVersion(appVersion, appVersionUpdateDto);
+ if (app.type === 'workflow') {
+ await this.appUtilService.updateWorflowVersion(appVersion, appVersionUpdateDto, app);
+ }
+
this.eventEmitter.emit('auditLogEntry', {
userId: user.id,
organizationId: user.organizationId,
diff --git a/server/src/modules/workflows/module.ts b/server/src/modules/workflows/module.ts
index 1e39e5123c..e71c52df50 100644
--- a/server/src/modules/workflows/module.ts
+++ b/server/src/modules/workflows/module.ts
@@ -98,6 +98,7 @@ export class WorkflowsModule {
UserRepository,
DataSourcesRepository,
DataQueryRepository,
+ DataSourcesRepository,
OrganizationConstantRepository,
VersionRepository,
AppsService,