({
getCustomResolvableReference: (value, parentId, moduleId) => {
const { getParentComponentType } = get();
const parentComponentType = getParentComponentType(parentId, moduleId);
- if (parentComponentType === 'Listview' && value.includes('listItem') && checkSubstringRegex(value, 'listItem')) {
+ if (
+ (parentComponentType === 'Listview' && value.includes('listItem') && checkSubstringRegex(value, 'listItem')) ||
+ value === '{{listItem}}'
+ ) {
return { entityType: 'components', entityNameOrId: parentId, entityKey: 'listItem' };
} else if (
parentComponentType === 'Kanban' &&
diff --git a/frontend/src/AppBuilder/_stores/slices/gridSlice.js b/frontend/src/AppBuilder/_stores/slices/gridSlice.js
index cc80a9dbf7..1958b8bece 100644
--- a/frontend/src/AppBuilder/_stores/slices/gridSlice.js
+++ b/frontend/src/AppBuilder/_stores/slices/gridSlice.js
@@ -3,6 +3,7 @@ import { debounce } from 'lodash';
const initialState = {
hoveredComponentForGrid: '',
+ hoveredComponentBoundaryId: '',
triggerCanvasUpdater: false,
lastCanvasIdClick: '',
lastCanvasClickPosition: null,
@@ -13,6 +14,8 @@ export const createGridSlice = (set, get) => ({
setHoveredComponentForGrid: (id) =>
set(() => ({ hoveredComponentForGrid: id }), false, { type: 'setHoveredComponentForGrid', id }),
getHoveredComponentForGrid: () => get().hoveredComponentForGrid,
+ setHoveredComponentBoundaryId: (id) =>
+ set(() => ({ hoveredComponentBoundaryId: id }), false, { type: 'setHoveredComponentBoundaryId', id }),
toggleCanvasUpdater: () =>
set((state) => ({ triggerCanvasUpdater: !state.triggerCanvasUpdater }), false, { type: 'toggleCanvasUpdater' }),
debouncedToggleCanvasUpdater: debounce(() => {
diff --git a/frontend/src/Editor/Components/DropdownV2/DropdownV2.jsx b/frontend/src/Editor/Components/DropdownV2/DropdownV2.jsx
index ae976e54ea..72e2b39664 100644
--- a/frontend/src/Editor/Components/DropdownV2/DropdownV2.jsx
+++ b/frontend/src/Editor/Components/DropdownV2/DropdownV2.jsx
@@ -61,7 +61,6 @@ export const DropdownV2 = ({
}) => {
const {
label,
- value,
advanced,
schema,
placeholder,
@@ -89,7 +88,7 @@ export const DropdownV2 = ({
padding,
} = styles;
const isInitialRender = useRef(true);
- const [currentValue, setCurrentValue] = useState(() => (advanced ? findDefaultItem(schema) : value));
+ const [currentValue, setCurrentValue] = useState(() => findDefaultItem(schema));
const isMandatory = validation?.mandatory ?? false;
const options = properties?.options;
const [validationStatus, setValidationStatus] = useState(validate(currentValue));
@@ -168,18 +167,9 @@ export const DropdownV2 = ({
};
useEffect(() => {
- if (advanced) {
- setInputValue(findDefaultItem(schema));
- }
+ setInputValue(findDefaultItem(advanced ? schema : options));
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [advanced, JSON.stringify(schema)]);
-
- useEffect(() => {
- if (!advanced) {
- setInputValue(value);
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [advanced, value]);
+ }, [advanced, JSON.stringify(schema), JSON.stringify(options)]);
useEffect(() => {
if (visibility !== properties.visibility) setVisibility(properties.visibility);
diff --git a/frontend/src/Editor/WidgetManager/configs/dropdownV2.js b/frontend/src/Editor/WidgetManager/configs/dropdownV2.js
index 247af3ccef..de90dbd0bf 100644
--- a/frontend/src/Editor/WidgetManager/configs/dropdownV2.js
+++ b/frontend/src/Editor/WidgetManager/configs/dropdownV2.js
@@ -299,7 +299,6 @@ export const dropdownV2Config = {
],
},
label: { value: 'Select' },
- value: { value: '{{"2"}}' },
optionsLoadingState: { value: '{{false}}' },
placeholder: { value: 'Select an option' },
visibility: { value: '{{true}}' },
diff --git a/frontend/src/Editor/WidgetManager/configs/listview.js b/frontend/src/Editor/WidgetManager/configs/listview.js
index a813bb5a0b..25da8f73c6 100644
--- a/frontend/src/Editor/WidgetManager/configs/listview.js
+++ b/frontend/src/Editor/WidgetManager/configs/listview.js
@@ -49,7 +49,13 @@ export const listviewConfig = {
type: 'code',
displayName: 'List data',
validation: {
- schema: { type: 'array', element: { type: 'object' } },
+ schema: {
+ type: 'union',
+ schemas: [
+ { type: 'array', element: { type: 'object' } },
+ { type: 'array', element: { type: 'string' } },
+ ],
+ },
defaultValue: "[{text: 'Sample text 1'}]",
},
},
diff --git a/frontend/src/_services/organization_constants.service.js b/frontend/src/_services/organization_constants.service.js
index 0ab57eb776..cd85a6fe15 100644
--- a/frontend/src/_services/organization_constants.service.js
+++ b/frontend/src/_services/organization_constants.service.js
@@ -15,7 +15,7 @@ export const orgEnvironmentConstantService = {
function getAll(type = null) {
const requestOptions = { method: 'GET', headers: authHeader(), credentials: 'include' };
const queryParams = type ? `?type=${type}` : '';
- return fetch(`${config.apiUrl}/organization-constants${queryParams}`, requestOptions).then(handleResponse);
+ return fetch(`${config.apiUrl}/organization-constants/decrypted${queryParams}`, requestOptions).then(handleResponse);
}
function create(name, value, type, environments) {
diff --git a/frontend/src/_styles/components.scss b/frontend/src/_styles/components.scss
index 5f742b2153..e84756dca7 100644
--- a/frontend/src/_styles/components.scss
+++ b/frontend/src/_styles/components.scss
@@ -493,4 +493,13 @@ $btn-dark-color: #FFFFFF;
}
}
}
+}
+
+//[Container-widget]Show scrollbar only on hover
+.widget-type-container {
+ overflow: hidden auto;
+ scrollbar-width: none;
+ &:hover {
+ scrollbar-width: auto;
+ }
}
\ No newline at end of file
diff --git a/frontend/src/_styles/table-component.scss b/frontend/src/_styles/table-component.scss
index 5e0edd5aff..82f6b3de71 100644
--- a/frontend/src/_styles/table-component.scss
+++ b/frontend/src/_styles/table-component.scss
@@ -1467,5 +1467,59 @@
}
.tj-table-tag-col-readonly {
- margin-left: -2px !important; //this -ve margin offset for the margin given to each tags in overall column width
-}
\ No newline at end of file
+ margin-left: -2px !important; //this -ve margin offset for the margin given to each tags in overall column width
+}
+
+.jet-data-table {
+ .table-bordered {
+ th,
+ td {
+ border-bottom: 1px solid var(--interactive-overlay-border-pressed) !important;
+ border-right: 1px solid var(--interactive-overlay-border-pressed) !important;
+
+ &:first-child {
+ border-left: none !important;
+ }
+
+ &:last-child {
+ border-right: none !important;
+ }
+ }
+
+ thead th {
+ border-top: none !important;
+
+ &:first-child {
+ border-left: none !important;
+ }
+
+ &:last-child {
+ border-right: none !important;
+ }
+ }
+ }
+
+ .table-striped {
+ tbody {
+ div[data-index]:nth-child(odd) {
+ background-color: transparent !important;
+ }
+
+ div[data-index]:nth-child(even) {
+ background-color: var(--slate2) !important;
+ }
+ }
+ }
+}
+
+@media (hover: none) and (pointer: coarse) {
+ .jet-data-table {
+ overflow: auto;
+ }
+ // hide scrollbar on touch devices
+ .jet-data-table::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+ background: transparent;
+ }
+}
diff --git a/frontend/src/_ui/Label.jsx b/frontend/src/_ui/Label.jsx
index 3cd7f886cb..721ac05203 100644
--- a/frontend/src/_ui/Label.jsx
+++ b/frontend/src/_ui/Label.jsx
@@ -13,6 +13,7 @@ function Label({ label, width, labelRef, color, defaultAlignment, direction, aut
justifyContent: direction == 'right' ? 'flex-end' : 'flex-start',
fontSize: '12px',
height: defaultAlignment === 'top' && '20px',
+ overflow: 'hidden',
}}
>
{
@@ -70,6 +71,23 @@ export class DataSourcesRepository extends Repository {
query.andWhere('data_source_options.environmentId = :environmentId', { environmentId });
}
const result = await query.getMany();
+ result.forEach((dataSource) => {
+ if (dataSource.plugin) {
+ if (dataSource.plugin.iconFile) {
+ dataSource.plugin.iconFile.data = dataSource.plugin.iconFile.data.toString('utf8');
+ }
+ if (dataSource.plugin.manifestFile) {
+ dataSource.plugin.manifestFile.data = JSON.parse(
+ decode(dataSource.plugin.manifestFile.data.toString('utf8'))
+ );
+ }
+ if (dataSource.plugin.operationsFile) {
+ dataSource.plugin.operationsFile.data = JSON.parse(
+ decode(dataSource.plugin.operationsFile.data.toString('utf8'))
+ );
+ }
+ }
+ });
const sampleDataSourceQuery = await manager
.createQueryBuilder(DataSource, 'data_source')
diff --git a/server/src/modules/group-permissions/constants/index.ts b/server/src/modules/group-permissions/constants/index.ts
index d63934d84f..091041661a 100644
--- a/server/src/modules/group-permissions/constants/index.ts
+++ b/server/src/modules/group-permissions/constants/index.ts
@@ -38,8 +38,8 @@ export const DEFAULT_GROUP_PERMISSIONS = {
appDelete: true,
folderCRUD: true,
orgConstantCRUD: true,
- dataSourceCreate: true,
- dataSourceDelete: true,
+ dataSourceCreate: false,
+ dataSourceDelete: false,
isBuilderLevel: true,
},
END_USER: {
diff --git a/server/src/modules/organization-constants/controller.ts b/server/src/modules/organization-constants/controller.ts
index 9a787ffb48..39862dee29 100644
--- a/server/src/modules/organization-constants/controller.ts
+++ b/server/src/modules/organization-constants/controller.ts
@@ -22,30 +22,51 @@ export class OrganizationConstantController implements IOrganizationConstantCont
@InitFeature(FEATURE_KEY.GET)
@Get()
async get(@User() user, @Query('type') type: OrganizationConstantType) {
- const result = await this.organizationConstantsService.allEnvironmentConstants(user.organizationId);
+ const result = await this.organizationConstantsService.allEnvironmentConstants(user.organizationId, false, type);
return { constants: result };
}
+ @UseGuards(JwtAuthGuard, FeatureAbilityGuard)
+ @InitFeature(FEATURE_KEY.GET_DECRYPTED_CONSTANTS)
+ @Get('decrypted')
+ async getDecryptedConstants(@User() user, @Query('type') type: OrganizationConstantType) {
+ const result = await this.organizationConstantsService.allEnvironmentConstants(user.organizationId, true, type);
+ return { constants: result };
+ }
+
+ @UseGuards(JwtAuthGuard, FeatureAbilityGuard)
+ @InitFeature(FEATURE_KEY.GET_SECRETS)
+ @Get('secrets')
+ async getAllSecrets(@User() user) {
+ const result = await this.organizationConstantsService.allEnvironmentConstants(
+ user.organizationId,
+ false,
+ OrganizationConstantType.SECRET
+ );
+ return { constants: result };
+ }
+
+ //by default, this api fetches only global constants (for public apps, need to fetch app to get orgId in the public guard)
@UseGuards(AppAuthGuard)
- @Get('public/:app_slug')
@InitFeature(FEATURE_KEY.GET_PUBLIC)
- async getConstantsFromPublicApp(@App() app, @Query('environmentId') environmentId) {
- const result = await this.organizationConstantsService.getConstantsForEnvironment(
+ @Get('public/:slug')
+ async getConstantsFromPublicApp(@App() app) {
+ const result = await this.organizationConstantsService.allEnvironmentConstants(
app.organizationId,
- environmentId,
+ false,
OrganizationConstantType.GLOBAL
);
return { constants: result };
}
//by default, this api fetches only global constants
- @UseGuards(JwtAuthGuard, FeatureAbilityGuard)
- @Get(':app_slug')
+ @UseGuards(JwtAuthGuard)
@InitFeature(FEATURE_KEY.GET_FROM_APP)
- async getConstantsFromApp(@User() user, @Query('environmentId') environmentId) {
- const result = await this.organizationConstantsService.getConstantsForEnvironment(
+ @Get(':app_slug')
+ async getConstantsFromApp(@User() user) {
+ const result = await this.organizationConstantsService.allEnvironmentConstants(
user.organizationId,
- environmentId,
+ false,
OrganizationConstantType.GLOBAL
);
return { constants: result };
diff --git a/server/src/modules/organization-constants/repository.ts b/server/src/modules/organization-constants/repository.ts
index 87e83cefdd..ddd1ba4b4a 100644
--- a/server/src/modules/organization-constants/repository.ts
+++ b/server/src/modules/organization-constants/repository.ts
@@ -10,9 +10,16 @@ export class OrganizationConstantRepository extends Repository {
return await dbTransactionWrap(async (manager: EntityManager) => {
- const result = await this.organizationConstantRepository.findAllByOrganizationId(organizationId);
+ const result = await this.organizationConstantRepository.findAllByOrganizationId(organizationId, type);
const appEnvironments = await this.appEnvironmentUtilService.getAll(organizationId);
const constantsWithValues = await Promise.all(
result.map(async (constant) => {
+ // Skip processing values if type is SECRET and decryptSecretValue is false
+ if (constant.type === OrganizationConstantType.SECRET && !decryptSecretValue) {
+ return {
+ name: constant.constantName,
+ };
+ }
const values = await Promise.all(
appEnvironments.map(async (env) => {
const value = constant.orgEnvironmentConstantValues.find((value) => value.environmentId === env.id);
+ let resolvedValue = '';
+ if (value) {
+ if (constant.type === OrganizationConstantType.SECRET) {
+ resolvedValue = decryptSecretValue
+ ? await this.organizationConstantsUtilService.decryptSecret(organizationId, value.value)
+ : secretValue;
+ } else {
+ resolvedValue = await this.organizationConstantsUtilService.decryptSecret(
+ organizationId,
+ value.value
+ ); // Constant type values are always decrypted
+ }
+ }
return {
environmentName: env.name,
- value:
- value && value.value.length > 0
- ? await this.organizationConstantsUtilService.decryptSecret(organizationId, value.value)
- : '',
- id: value.environmentId,
+ value: resolvedValue,
};
})
);
@@ -62,22 +77,26 @@ export class OrganizationConstantsService implements IOrganizationConstantsServi
environmentId: string,
type?: OrganizationConstantType
): Promise {
- return await dbTransactionWrap(async (manager: EntityManager) => {
- const result = await this.organizationConstantRepository.findByEnvironment(organizationId, environmentId);
+ return dbTransactionWrap(async (manager: EntityManager) => {
+ const result = await this.organizationConstantRepository.findByEnvironment(organizationId, environmentId, type);
- const constantsWithValues = result.map(async (constant) => {
- const decryptedValue = await this.organizationConstantsUtilService.decryptSecret(
- organizationId,
- constant.orgEnvironmentConstantValues[0].value
- );
- return {
- id: constant.id,
- name: constant.constantName,
- value: decryptedValue,
- };
- });
+ return await Promise.all(
+ result.map(async (constant) => {
+ const resolvedValue = !(constant.type === OrganizationConstantType.SECRET)
+ ? await this.organizationConstantsUtilService.decryptSecret(
+ organizationId,
+ constant.orgEnvironmentConstantValues[0].value
+ )
+ : secretValue;
- return Promise.all(constantsWithValues);
+ return {
+ id: constant.id,
+ name: constant.constantName,
+ type: constant.type,
+ value: resolvedValue,
+ };
+ })
+ );
});
}
diff --git a/server/src/modules/organization-users/service.ts b/server/src/modules/organization-users/service.ts
index 77165b19b1..93f8a15a9e 100644
--- a/server/src/modules/organization-users/service.ts
+++ b/server/src/modules/organization-users/service.ts
@@ -193,138 +193,136 @@ export class OrganizationUsersService implements IOrganizationUsersService {
let invalidGroups = [];
const emailPattern = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
const invalidRoles = [];
- await dbTransactionWrap(async (manager: EntityManager) => {
- const groupPermissions = (
- await this.groupPermissionsUtilService.getAllGroupByOrganization(currentUser.organizationId)
- ).groupPermissions?.filter((gp) => !gp.disabled);
- const existingGroups = groupPermissions.map((groupPermission) => groupPermission.name);
- csv
- .parseString(fileStream.toString(), {
- headers: ['first_name', 'last_name', 'email', 'user_role', 'groups', 'metadata'],
- renameHeaders: true,
- ignoreEmpty: true,
- })
- .transform((row: UserCsvRow, next) => {
- const groupNames = this.organizationUsersUtilService.createGroupsList(row?.groups);
- invalidGroups = [...invalidGroups, ...groupNames.filter((group) => !existingGroups.includes(group))];
- const groups = groupPermissions.filter((group) => groupNames.includes(group.name)).map((group) => group.id);
- return next(null, {
- ...row,
- groups: groups,
- user_role: this.organizationUsersUtilService.convertUserRolesCasing(row?.user_role),
- userMetadata: row?.metadata ? JSON.parse(row.metadata) : null,
- email: row?.email?.toLowerCase(),
- });
- })
- .validate(async (data: UserCsvRow, next) => {
- await dbTransactionWrap(async (manager: EntityManager) => {
- //Check for existing users
- let isInvalidRole = false;
-
- const user = await this.userRepository.findByEmail(data?.email, undefined, undefined, manager);
-
- if (user?.status === USER_STATUS.ARCHIVED) {
- archivedUsers.push(data?.email);
- } else if (user?.organizationUsers?.some((ou) => ou.organizationId === currentUser.organizationId)) {
- existingUsers.push(data?.email);
- } else {
- const user = {
- firstName: data?.first_name,
- lastName: data?.last_name,
- email: data?.email,
- role: data?.user_role,
- groups: data?.groups,
- userMetadata: data?.metadata,
- };
- users.push(user);
- }
-
- //Check for invalid groups
-
- if (!Object.values(USER_ROLE).includes(data?.user_role as USER_ROLE)) {
- invalidRoles.push(data?.user_role);
- isInvalidRole = true;
- }
-
- data.first_name = data.first_name?.trim();
- data.last_name = data.last_name?.trim();
-
- const isValidName = data.first_name !== '' || data.last_name !== '';
- return next(null, isValidName && emailPattern.test(data.email) && !isInvalidRole);
- }, manager);
- })
- .on('data', function () {})
- .on('data-invalid', (row, rowNumber) => {
- const invalidField = Object.keys(row).filter((key) => {
- if (Array.isArray(row[key])) {
- return row[key].length === 0;
- }
- return !row[key] || row[key] === '';
- });
- invalidRows.push(rowNumber);
- invalidFields.add(invalidField);
- })
- .on('end', async (rowCount: number) => {
- try {
- if (rowCount > MAX_ROW_COUNT) {
- throw new BadRequestException('Row count cannot be greater than 500');
- }
-
- if (invalidRows.length) {
- const invalidFieldsArray = invalidFields.entries().next().value[1];
- const errorMsg = `Missing ${[invalidFieldsArray.join(',')]} information in ${
- invalidRows.length
- } row(s);. No users were uploaded, please update and try again.`;
- throw new BadRequestException(errorMsg);
- }
-
- if (invalidGroups.length) {
- throw new BadRequestException(
- `${invalidGroups.length} group${isPlural(invalidGroups)} doesn't exist. No users were uploaded`
- );
- }
-
- if (invalidRoles.length > 0) {
- throw new BadRequestException('Invalid role present for the users');
- }
-
- if (archivedUsers.length) {
- throw new BadRequestException(
- `User${isPlural(archivedUsers)} with email ${archivedUsers.join(
- ', '
- )} is archived. No users were uploaded`
- );
- }
-
- if (existingUsers.length) {
- throw new BadRequestException(
- `${existingUsers.length} users with same email already exist. No users were uploaded `
- );
- }
-
- if (users.length === 0) {
- throw new BadRequestException('No users were uploaded');
- }
-
- if (users.length > 250) {
- throw new BadRequestException(`You can only invite 250 users at a time`);
- }
-
- await this.organizationUsersUtilService.inviteUserswrapper(users, currentUser);
- res.status(201).send({ message: `${rowCount} user${isPlural(users)} are being added` });
- } catch (error) {
- const { status, response } = error;
- if (status === 451) {
- res.status(status).send({ message: response, statusCode: status });
- return;
- }
- res.status(status).send(JSON.stringify(response));
- }
- })
- .on('error', (error) => {
- throw error.message;
+ const groupPermissions = (
+ await this.groupPermissionsUtilService.getAllGroupByOrganization(currentUser.organizationId)
+ ).groupPermissions?.filter((gp) => !gp.disabled);
+ const existingGroups = groupPermissions.map((groupPermission) => groupPermission.name);
+ csv
+ .parseString(fileStream.toString(), {
+ headers: ['first_name', 'last_name', 'email', 'user_role', 'groups', 'metadata'],
+ renameHeaders: true,
+ ignoreEmpty: true,
+ })
+ .transform((row: UserCsvRow, next) => {
+ const groupNames = this.organizationUsersUtilService.createGroupsList(row?.groups);
+ invalidGroups = [...invalidGroups, ...groupNames.filter((group) => !existingGroups.includes(group))];
+ const groups = groupPermissions.filter((group) => groupNames.includes(group.name)).map((group) => group.id);
+ return next(null, {
+ ...row,
+ groups: groups,
+ user_role: this.organizationUsersUtilService.convertUserRolesCasing(row?.user_role),
+ userMetadata: row?.metadata ? JSON.parse(row.metadata) : null,
+ email: row?.email?.toLowerCase(),
});
- });
+ })
+ .validate(async (data: UserCsvRow, next) => {
+ await dbTransactionWrap(async (manager: EntityManager) => {
+ //Check for existing users
+ let isInvalidRole = false;
+
+ const user = await this.userRepository.findByEmail(data?.email, undefined, undefined, manager);
+
+ if (user?.status === USER_STATUS.ARCHIVED) {
+ archivedUsers.push(data?.email);
+ } else if (user?.organizationUsers?.some((ou) => ou.organizationId === currentUser.organizationId)) {
+ existingUsers.push(data?.email);
+ } else {
+ const user = {
+ firstName: data?.first_name,
+ lastName: data?.last_name,
+ email: data?.email,
+ role: data?.user_role,
+ groups: data?.groups,
+ userMetadata: data?.metadata,
+ };
+ users.push(user);
+ }
+
+ //Check for invalid groups
+
+ if (!Object.values(USER_ROLE).includes(data?.user_role as USER_ROLE)) {
+ invalidRoles.push(data?.user_role);
+ isInvalidRole = true;
+ }
+
+ data.first_name = data.first_name?.trim();
+ data.last_name = data.last_name?.trim();
+
+ const isValidName = data.first_name !== '' || data.last_name !== '';
+ return next(null, isValidName && emailPattern.test(data.email) && !isInvalidRole);
+ });
+ })
+ .on('data', function () {})
+ .on('data-invalid', (row, rowNumber) => {
+ const invalidField = Object.keys(row).filter((key) => {
+ if (Array.isArray(row[key])) {
+ return row[key].length === 0;
+ }
+ return !row[key] || row[key] === '';
+ });
+ invalidRows.push(rowNumber);
+ invalidFields.add(invalidField);
+ })
+ .on('end', async (rowCount: number) => {
+ try {
+ if (rowCount > MAX_ROW_COUNT) {
+ throw new BadRequestException('Row count cannot be greater than 500');
+ }
+
+ if (invalidRows.length) {
+ const invalidFieldsArray = invalidFields.entries().next().value[1];
+ const errorMsg = `Missing ${[invalidFieldsArray.join(',')]} information in ${
+ invalidRows.length
+ } row(s);. No users were uploaded, please update and try again.`;
+ throw new BadRequestException(errorMsg);
+ }
+
+ if (invalidGroups.length) {
+ throw new BadRequestException(
+ `${invalidGroups.length} group${isPlural(invalidGroups)} doesn't exist. No users were uploaded`
+ );
+ }
+
+ if (invalidRoles.length > 0) {
+ throw new BadRequestException('Invalid role present for the users');
+ }
+
+ if (archivedUsers.length) {
+ throw new BadRequestException(
+ `User${isPlural(archivedUsers)} with email ${archivedUsers.join(
+ ', '
+ )} is archived. No users were uploaded`
+ );
+ }
+
+ if (existingUsers.length) {
+ throw new BadRequestException(
+ `${existingUsers.length} users with same email already exist. No users were uploaded `
+ );
+ }
+
+ if (users.length === 0) {
+ throw new BadRequestException('No users were uploaded');
+ }
+
+ if (users.length > 250) {
+ throw new BadRequestException(`You can only invite 250 users at a time`);
+ }
+
+ await this.organizationUsersUtilService.inviteUserswrapper(users, currentUser);
+ res.status(201).send({ message: `${rowCount} user${isPlural(users)} are being added` });
+ } catch (error) {
+ const { status, response } = error;
+ if (status === 451) {
+ res.status(status).send({ message: response, statusCode: status });
+ return;
+ }
+ res.status(status).send(JSON.stringify(response));
+ }
+ })
+ .on('error', (error) => {
+ throw error.message;
+ });
}
async fetchUsersByValue(organizationId: string, searchInput: string) {
diff --git a/server/src/modules/workflows/module.ts b/server/src/modules/workflows/module.ts
index 3ee0f2a02b..1e39e5123c 100644
--- a/server/src/modules/workflows/module.ts
+++ b/server/src/modules/workflows/module.ts
@@ -28,6 +28,7 @@ import { AppsAbilityFactory } from '@modules/casl/abilities/apps-ability.factory
import { WorkflowSchedule } from '@entities/workflow_schedule.entity';
import { App } from '@entities/app.entity';
import { AiModule } from '@modules/ai/module';
+import { DataSourcesRepository } from '@modules/data-sources/repository';
export class WorkflowsModule {
static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise {
const importPath = await getImportPath(configs?.IS_GET_CONTEXT);
@@ -95,6 +96,7 @@ export class WorkflowsModule {
AppsAbilityFactory,
AppsRepository,
UserRepository,
+ DataSourcesRepository,
DataQueryRepository,
OrganizationConstantRepository,
VersionRepository,