Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
88f7b32
feat: Uncommited the crone expression and removed the static one
thisismayuresh Sep 12, 2025
381702b
feat: Uncommited the cron expression and removed the static one (#1074)
thisismayuresh Sep 12, 2025
a76c0fb
feat: Removed the ScheduledRegistry Cron
thisismayuresh Sep 12, 2025
eb3fee5
feat: Removed the ScheduleUserJob
thisismayuresh Sep 12, 2025
4db921a
feat: Removed the ScheduledRegistry Cron (#1075)
thisismayuresh Sep 12, 2025
04387bc
feat: Added 5 Minutes Corn
thisismayuresh Sep 12, 2025
f2def33
feat: Added 5 Minutes Corn (#1076)
thisismayuresh Sep 12, 2025
c1f9713
fix: Prevented the non required columns from being flagged as invalid
thisismayuresh Sep 13, 2025
880bb7f
Merge branch 'next' into fix/optional-columns-marked-invalid
thisismayuresh Sep 13, 2025
b130cfc
fix: Prevented the non required columns from being flagged as invalid…
thisismayuresh Sep 13, 2025
30b9ef6
feat: Removed the Redundant UserJobTrigger
thisismayuresh Sep 13, 2025
34c6c8c
fix: Corrected Failed Build
thisismayuresh Sep 13, 2025
5444d95
feat: Added Log for making new build
thisismayuresh Sep 13, 2025
22923d1
Merge branch 'next' into fix/build
thisismayuresh Sep 13, 2025
f089208
Fix/build (#1078)
thisismayuresh Sep 13, 2025
aaf3286
feat: Added the areInvalidRecords in the sendDataImportData
thisismayuresh Sep 15, 2025
638d248
Merge branch 'next' into feat/isInvalidRecord-on-every-page
thisismayuresh Sep 15, 2025
5dc70b3
feat: Added the areInvalidRecords in the sendDataImportData (#1080)
thisismayuresh Sep 15, 2025
0f7df50
feat: Removed the Scheduled Registry
thisismayuresh Sep 15, 2025
dd99815
feat: Removed the Scheduled Registry
thisismayuresh Sep 15, 2025
a2c922c
Feat/is invalid record on every page (#1081)
thisismayuresh Sep 15, 2025
d1a5c0d
feat: Removed the Redundant method call sendDataImportData
thisismayuresh Sep 15, 2025
b6c6d06
feat: Removed the Redundant method call sendDataImportData (#1082)
thisismayuresh Sep 15, 2025
624a063
feat: Added the Revamped modal of the Import History Modal with Retry
thisismayuresh Sep 18, 2025
3044285
feat: Added the Sample Webhook data on the destination url if provided
thisismayuresh Sep 19, 2025
f446e23
feat: Added the Modal to open authHeaderValue before opening the Impo…
thisismayuresh Sep 22, 2025
201ab03
feat: Removed the authheaderValue from the Modal
thisismayuresh Sep 22, 2025
25a58d1
feat: Removed the live fetching from the useHistory hook
thisismayuresh Sep 22, 2025
ed62043
feat: Added the authHeaderValue in both of the Modals
thisismayuresh Sep 22, 2025
a3deeeb
feat: Parsed the extra data
thisismayuresh Sep 22, 2025
78991b3
feat: Updated the classes as the jsx based
thisismayuresh Sep 22, 2025
d2bc146
feat: Added the IntersectionObserver based infinite scroll
thisismayuresh Sep 23, 2025
9ce3615
feat: Added the delay in fetching logs
thisismayuresh Sep 23, 2025
07c28b9
feat: Added 1 second delay in fetching logs
thisismayuresh Sep 23, 2025
88ce110
Feat/webhook retry revamped (#1083)
thisismayuresh Sep 23, 2025
bb763f7
chore: add .vscode/ to .gitignore
thisismayuresh Sep 23, 2025
ecd28d7
chore: add .vscode/ to .gitignore
thisismayuresh Sep 23, 2025
85b0e60
v1.8.0
thisismayuresh Sep 23, 2025
367e300
feat: Updated docker-compose images version
thisismayuresh Sep 23, 2025
668041d
Release/1.8.0 (#1087)
thisismayuresh Sep 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
node_modules
dist
build

.vscode/
.env
.nx
.nx
14 changes: 0 additions & 14 deletions .vscode/settings.json

This file was deleted.

3 changes: 2 additions & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@impler/api",
"version": "1.7.0",
"version": "1.8.0",
"author": "implerhq",
"license": "MIT",
"private": true,
Expand All @@ -23,6 +23,7 @@
},
"dependencies": {
"@amplitude/analytics-node": "^1.3.6",
"@faker-js/faker": "^8.4.1",
"@impler/client": "workspace:^",
"@impler/dal": "workspace:^",
"@impler/services": "workspace:^",
Expand Down
39 changes: 36 additions & 3 deletions apps/api/src/app/activity/activity.controller.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { ApiTags, ApiOperation, ApiSecurity } from '@nestjs/swagger';
import { Controller, Param, UseGuards, Get, Query } from '@nestjs/common';
import { Controller, Param, UseGuards, Get, Query, Post } from '@nestjs/common';
import { ValidateMongoId } from '@shared/validations/valid-mongo-id.validation';

import { UploadSummary, UploadHistory } from './usecases';
import { UploadSummary, UploadHistory, RetryUpload, WebhookLogs } from './usecases';
import { ACCESS_KEY_NAME, Defaults } from '@impler/shared';
import { JwtAuthGuard } from '@shared/framework/auth.gaurd';
import { isDateString } from '@shared/helpers/common.helper';
Expand All @@ -14,7 +14,9 @@ import { isDateString } from '@shared/helpers/common.helper';
export class ActivityController {
constructor(
private uploadSummary: UploadSummary,
private uploadHistory: UploadHistory
private uploadHistory: UploadHistory,
private retryUpload: RetryUpload,
private webhookLogs: WebhookLogs
) {}

@Get(':projectId/summary')
Expand Down Expand Up @@ -52,4 +54,35 @@ export class ActivityController {
limit,
});
}

@Post(':uploadId/retry')
@ApiOperation({
summary: 'Retry webhook data for a specific upload',
})
async retryUploadRoute(@Param('uploadId', ValidateMongoId) uploadId: string) {
return this.retryUpload.execute(uploadId);
}

@Get('upload/:uploadId/webhook-logs')
@ApiOperation({
summary: 'Get webhook logs for a specific upload',
})
async getWebhookLogsRoute(
@Param('uploadId', ValidateMongoId) uploadId: string,
@Query('page') page = Defaults.ONE,
@Query('limit') limit = Defaults.PAGE_LIMIT,
@Query('isRetry') isRetry?: boolean
) {
if (isNaN(page)) page = Defaults.ONE;
else page = Number(page);
if (isNaN(limit)) limit = Defaults.PAGE_LIMIT;
else limit = Number(limit);

return this.webhookLogs.execute({
uploadId,
page,
limit,
isRetry,
});
}
}
16 changes: 10 additions & 6 deletions apps/api/src/app/activity/usecases/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { UploadSummary } from './upload-summary/upload-summary.usecase';
import { UploadHistory } from './upload-history/upload-history.usecase';
import { RetryUpload } from './retry-upload/retry-upload.usecase';
import { WebhookLogs } from './webhook-logs/webhook-logs.usecase';
import { QueueService } from '@shared/services/queue.service';

export const USE_CASES = [
UploadSummary,
UploadHistory,
//
];
export * from './upload-summary/upload-summary.usecase';
export * from './upload-history/upload-history.usecase';
export * from './retry-upload/retry-upload.usecase';
export * from './webhook-logs/webhook-logs.usecase';

export { UploadSummary, UploadHistory };
export const USE_CASES = [UploadSummary, UploadHistory, RetryUpload, WebhookLogs, QueueService];

export { UploadSummary, UploadHistory, RetryUpload, WebhookLogs, QueueService };
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { UploadRepository, TemplateRepository, WebhookDestinationRepository } from '@impler/dal';
import { QueueService } from '@shared/services/queue.service';
import { QueuesEnum, DestinationsEnum } from '@impler/shared';

@Injectable()
export class RetryUpload {
constructor(
private uploadRepository: UploadRepository,
private templateRepository: TemplateRepository,
private webhookDestinationRepository: WebhookDestinationRepository,
private queueService: QueueService
) {}

async execute(uploadId: string) {
const upload = await this.uploadRepository.findById(uploadId);

if (!upload) {
throw new Error('Upload not found');
}

const template = await this.templateRepository.findOne({ _id: upload._templateId });

if (!template || template.destination !== DestinationsEnum.WEBHOOK) {
throw new BadRequestException('Template does not have a webhook destination');
}

const webhookDestination = await this.webhookDestinationRepository.findOne({ _templateId: upload._templateId });

if (!webhookDestination) {
throw new BadRequestException('Webhook destination not found for template');
}

this.queueService.publishToQueue(QueuesEnum.SEND_WEBHOOK_DATA, {
uploadId: upload._id,
isRetry: true,
});

return {
success: true,
message: 'Retry request queued successfully',
upload: upload,
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { IsDefined, IsMongoId, IsOptional, IsNumber, Min } from 'class-validator';
import { Transform } from 'class-transformer';

export class WebhookLogsCommand {
@IsDefined()
@IsMongoId()
uploadId: string;

@IsOptional()
@Transform(({ value }) => Number(value))
@IsNumber()
@Min(1)
page?: number = 1;

@IsOptional()
@Transform(({ value }) => Number(value))
@IsNumber()
@Min(1)
limit?: number = 10;

@IsOptional()
isRetry?: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Injectable } from '@nestjs/common';
import { WebhookLogRepository } from '@impler/dal';
import { PaginationResult } from '@impler/shared';
import { WebhookLogsCommand } from './webhook-logs.command';

@Injectable()
export class WebhookLogs {
constructor(private webhookLogRepository: WebhookLogRepository) {}

async execute({ uploadId, page = 1, limit = 10, isRetry }: WebhookLogsCommand): Promise<PaginationResult> {
const skip = (page - 1) * limit;

const matchQuery: any = { _uploadId: uploadId };
if (isRetry !== undefined) {
matchQuery.isRetry = isRetry;
}

const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
matchQuery.callDate = { $gte: thirtyDaysAgo };

const [logs, totalCount] = await Promise.all([
this.webhookLogRepository.find(matchQuery, '', {
sort: { createdAt: -1 },
skip,
limit,
}),
this.webhookLogRepository.count(matchQuery),
]);

return {
data: logs,
limit,
page,
totalPages: Math.ceil(totalCount / limit),
totalRecords: totalCount,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { Injectable } from '@nestjs/common';
import * as dayjs from 'dayjs';
import * as parser from 'cron-parser';
import { Cron } from '@nestjs/schedule';
import { ScheduleUserJob, UpdateUserJob } from 'app/import-jobs/usecase';
import { UpdateUserJob } from 'app/import-jobs/usecase';
import { UserJobImportStatusEnum } from '@impler/shared';
import { UserJobTriggerService } from 'app/import-jobs/usecase';
import { CRON_SCHEDULE } from '@shared/constants';
// import { CRON_SCHEDULE } from '@shared/constants';
const parseCronExpression = require('@impler/shared/src/utils/cronstrue');

@Injectable()
Expand All @@ -15,11 +15,12 @@ export class AutoImportJobsSchedular {
private readonly userJobRepository: UserJobRepository,
private readonly webhookDestinationRepository: WebhookDestinationRepository,
private readonly updateUserJob: UpdateUserJob,
private readonly scheduleUserJob: ScheduleUserJob
private readonly userJobTriggerService: UserJobTriggerService
) {}

@Cron(CRON_SCHEDULE.AUTO_IMPORT_DEFAULT_CRON_TIME)
async handleCronSchedular() {
console.log('Crone Running');
await this.fetchAndExecuteScheduledJobs();
}

Expand All @@ -28,6 +29,7 @@ export class AutoImportJobsSchedular {
const userJobs = await this.userJobRepository.find({});

for (const userJob of userJobs) {
console.log('Should run the Cron Job ?', await this.shouldCroneRun({ userJob }), userJob._id);
if (await this.shouldCroneRun({ userJob })) {
try {
const interval = parser.parseExpression(userJob.cron);
Expand All @@ -39,7 +41,8 @@ export class AutoImportJobsSchedular {

await this.updateUserJob.execute(userJob._id, userJob);

await this.scheduleUserJob.execute(userJob._id, userJob.cron);
// await this.scheduleUserJob.execute(userJob._id, userJob.cron);
await this.userJobTriggerService.execute(userJob._id);
}
} catch (error) {}
}
Expand Down Expand Up @@ -89,10 +92,16 @@ export class AutoImportJobsSchedular {
async shouldCroneRun({ userJob }: { userJob: UserJobEntity }): Promise<boolean> {
const now = dayjs();

if (userJob.status === UserJobImportStatusEnum.PAUSED) {
return false;
}

if (
(userJob.cron && userJob.status === UserJobImportStatusEnum.SCHEDULING) ||
userJob.status === UserJobImportStatusEnum.RUNNING ||
(userJob.status === 'Completed' && (await this.fetchDestination(userJob._templateId)) && !userJob.endsOn) ||
(userJob.status === UserJobImportStatusEnum.COMPLETED &&
(await this.fetchDestination(userJob._templateId)) &&
!userJob.endsOn) ||
!dayjs(userJob.endsOn).isSame(now, 'd')
) {
return true;
Expand Down
3 changes: 1 addition & 2 deletions apps/api/src/app/auto-import-jobs-schedular/usecase/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ScheduleUserJob, UpdateUserJob, UserJobTriggerService } from 'app/import-jobs/usecase';
import { UpdateUserJob, UserJobTriggerService } from 'app/import-jobs/usecase';
import { AutoImportJobsSchedular } from './auto-import-jobs-schedular';
import { QueueService } from '@shared/services/queue.service';

Expand All @@ -7,7 +7,6 @@ export const USE_CASES = [
UpdateUserJob,
UserJobTriggerService,
UserJobTriggerService,
ScheduleUserJob,
QueueService,
//
];
Expand Down
3 changes: 0 additions & 3 deletions apps/api/src/app/import-jobs/usecase/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { UserJobDelete } from './userjob-usecase/userjob-delete.usecase';
import { UserJobTerminate } from './userjob-usecase/userjob-terminate.usecase';
import { UserJobTriggerService } from './userjob-usecase/userjob-trigger.usecase';
import { UserJobResume } from './userjob-usecase/userjob.resume.usecsae';
import { ScheduleUserJob } from './schedule-user-job/schedule-user-job';

export const USECASES = [
CreateUserJob,
Expand All @@ -25,7 +24,6 @@ export const USECASES = [
UserJobDelete,
UserJobTerminate,
UserJobTriggerService,
ScheduleUserJob,
//
];

Expand All @@ -40,5 +38,4 @@ export {
UserJobDelete,
UserJobTerminate,
UserJobTriggerService,
ScheduleUserJob,
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { Injectable } from '@nestjs/common';
import { SchedulerRegistry } from '@nestjs/schedule';
import { NameService } from '@impler/services';
import { UserJobEntity, UserJobRepository } from '@impler/dal';
import { DocumentNotFoundException } from '@shared/exceptions/document-not-found.exception';

@Injectable()
export class UserJobDelete {
constructor(
private readonly nameService: NameService,
private readonly schedulerRegistry: SchedulerRegistry,
private readonly userJobRepository: UserJobRepository
) {}
constructor(private readonly userJobRepository: UserJobRepository) {}

async execute({ externalUserId, _jobId }: { externalUserId: string; _jobId: string }): Promise<UserJobEntity> {
const userJobToDelete = await this.userJobRepository.findOne({ _id: _jobId, externalUserId });
Expand All @@ -24,11 +18,9 @@ export class UserJobDelete {
}

try {
this.schedulerRegistry.deleteCronJob(this.nameService.getCronName(_jobId));
await this.userJobRepository.delete({ _id: _jobId });
} catch (error) {}

await this.userJobRepository.delete({ _id: _jobId });

return userJobToDelete;
}
}
Loading
Loading