mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-30 03:00:57 +00:00
Merge pull request #597 from MostafaAmin07/gitlab-fix-and-optimization
Gitlab fix and optimization
This commit is contained in:
commit
4d15e274d8
5 changed files with 185 additions and 29 deletions
|
|
@ -19,5 +19,13 @@ export interface IssueServiceInterface {
|
|||
issue: IssueData
|
||||
} | null>;
|
||||
|
||||
refreshIssues?(tasks: Task[],
|
||||
isNotifySuccess: boolean,
|
||||
isNotifyNoUpdateRequired: boolean): Promise<{
|
||||
task: Task,
|
||||
taskChanges: Partial<Task>,
|
||||
issue: IssueData
|
||||
}[]>;
|
||||
|
||||
getMappedAttachments?(issueDataIN: IssueData): TaskAttachment[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,50 @@ export class IssueService {
|
|||
}
|
||||
}
|
||||
|
||||
async refreshIssues(
|
||||
tasks: Task[],
|
||||
isNotifySuccess: boolean = true,
|
||||
isNotifyNoUpdateRequired: boolean = false
|
||||
): Promise<void> {
|
||||
// dynamic map that has a list of tasks for every entry where the entry is an issue type
|
||||
const tasksIssueIdsByIssueType: any = {};
|
||||
const tasksWithoutIssueId = [];
|
||||
const tasksWithoutMethod = [];
|
||||
|
||||
for (const task of tasks) {
|
||||
if (!task.issueId || !task.issueType) {
|
||||
tasksWithoutIssueId.push(task);
|
||||
} else if (!this.ISSUE_SERVICE_MAP[task.issueType].refreshIssues) {
|
||||
tasksWithoutMethod.push(task);
|
||||
}
|
||||
else if (!tasksIssueIdsByIssueType[task.issueType]){
|
||||
tasksIssueIdsByIssueType[task.issueType] = [];
|
||||
tasksIssueIdsByIssueType[task.issueType].push(task);
|
||||
} else {
|
||||
tasksIssueIdsByIssueType[task.issueType].push(task);
|
||||
}
|
||||
}
|
||||
|
||||
for (const issuesType of Object.keys(tasksIssueIdsByIssueType)) {
|
||||
const updates = await (this.ISSUE_SERVICE_MAP[issuesType].refreshIssues as any)(tasksIssueIdsByIssueType[issuesType], isNotifySuccess, isNotifyNoUpdateRequired);
|
||||
if (updates) {
|
||||
for (const update of updates) {
|
||||
if (this.ISSUE_REFRESH_MAP[issuesType][update.task.issueId]) {
|
||||
this.ISSUE_REFRESH_MAP[issuesType][update.task.issueId].next(update.issue);
|
||||
}
|
||||
this._taskService.update(update.task.id, update.taskChanges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const taskWithoutIssueId of tasksWithoutIssueId) {
|
||||
throw new Error('No issue task ' + taskWithoutIssueId.id);
|
||||
}
|
||||
for (const taskWithoutMethod of tasksWithoutMethod) {
|
||||
throw new Error('Issue method not available ' + taskWithoutMethod);
|
||||
}
|
||||
}
|
||||
|
||||
async addTaskWithIssue(
|
||||
issueType: IssueProviderKey,
|
||||
issueIdOrData: string | number | IssueDataReduced,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { GitlabOriginalComment, GitlabOriginalIssue } from './gitlab-api-respons
|
|||
import { HANDLED_ERROR_PROP_STR } from 'src/app/app.constants';
|
||||
import { GITLAB_API_BASE_URL, GITLAB_URL_REGEX, GITLAB_PROJECT_REGEX } from '../gitlab.const';
|
||||
import { T } from 'src/app/t.const';
|
||||
import { catchError, filter, map, mergeMap, share, switchMap, take } from 'rxjs/operators';
|
||||
import { catchError, filter, map, mergeMap, take } from 'rxjs/operators';
|
||||
import { GitlabIssue } from '../gitlab-issue/gitlab-issue.model';
|
||||
import { mapGitlabIssue, mapGitlabIssueToSearchResult } from '../gitlab-issue/gitlab-issue-map.util';
|
||||
import { SearchResultItem } from '../../../issue.model';
|
||||
|
|
@ -42,10 +42,41 @@ export class GitlabApiService {
|
|||
}
|
||||
|
||||
getById$(id: number, cfg: GitlabCfg): Observable<GitlabIssue> {
|
||||
return this.getProjectData$(cfg)
|
||||
.pipe(switchMap(issues => {
|
||||
return issues.filter(issue => issue.id === id);
|
||||
}));
|
||||
return this._sendRequest$({
|
||||
url: `${this.apiLink(cfg)}/issues/${id}`
|
||||
}, cfg).pipe(
|
||||
mergeMap(
|
||||
(issue: GitlabOriginalIssue) => {
|
||||
return this.getIssueWithComments$(mapGitlabIssue(issue), cfg);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getByIds$(ids: string[], cfg: GitlabCfg): Observable<GitlabIssue[]> {
|
||||
let queryParams = 'iids[]=';
|
||||
for (let i = 0; i < ids.length ; i++) {
|
||||
if (i === ids.length - 1) {
|
||||
queryParams += ids[i];
|
||||
} else {
|
||||
queryParams += `${ids[i]}&iids[]=`;
|
||||
}
|
||||
}
|
||||
return this._sendRequest$({
|
||||
url: `${this.apiLink(cfg)}/issues?${queryParams}&per_page=100`
|
||||
}, cfg).pipe(
|
||||
map((issues: GitlabOriginalIssue[]) => {
|
||||
return issues ? issues.map(mapGitlabIssue) : [];
|
||||
}),
|
||||
mergeMap((issues: GitlabIssue[]) => {
|
||||
if (issues && issues.length) {
|
||||
return forkJoin([
|
||||
...issues.map(issue => this.getIssueWithComments$(issue, cfg))
|
||||
]);
|
||||
} else {
|
||||
return of([]);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
getIssueWithComments$(issue: GitlabIssue, cfg: GitlabCfg): Observable<GitlabIssue> {
|
||||
|
|
@ -61,32 +92,34 @@ export class GitlabApiService {
|
|||
}
|
||||
|
||||
searchIssueInProject$(searchText: string, cfg: GitlabCfg): Observable<SearchResultItem[]> {
|
||||
const filterFn = (issue: GitlabIssue) => {
|
||||
try {
|
||||
return issue.title.toLowerCase().match(searchText.toLowerCase())
|
||||
|| issue.body.toLowerCase().match(searchText.toLowerCase());
|
||||
} catch (e) {
|
||||
console.warn('RegEx Error', e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
if (!this._isValidSettings(cfg)) {
|
||||
return EMPTY;
|
||||
}
|
||||
return this.getProjectData$(cfg)
|
||||
.pipe(
|
||||
// a single request should suffice
|
||||
share(),
|
||||
map((issues: GitlabIssue[]) =>
|
||||
issues.filter(filterFn)
|
||||
.map(mapGitlabIssueToSearchResult)
|
||||
),
|
||||
);
|
||||
return this._sendRequest$({
|
||||
url: `${this.apiLink(cfg)}/issues?search=${searchText}&order_by=updated_at`
|
||||
}, cfg).pipe(
|
||||
map((issues: GitlabOriginalIssue[]) => {
|
||||
return issues ? issues.map(mapGitlabIssue) : [];
|
||||
}),
|
||||
mergeMap(
|
||||
(issues: GitlabIssue[]) => {
|
||||
if (issues && issues.length) {
|
||||
return forkJoin([
|
||||
...issues.map(issue => this.getIssueWithComments$(issue, cfg))
|
||||
]);
|
||||
} else {
|
||||
return of([]);
|
||||
}
|
||||
}),
|
||||
map((issues: GitlabIssue[]) => {
|
||||
return issues ? issues.map(mapGitlabIssueToSearchResult) : [];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private _getProjectIssues$(pageNumber: number, cfg: GitlabCfg): Observable<GitlabIssue[]> {
|
||||
return this._sendRequest$({
|
||||
url: `${this.apiLink(cfg)}/issues?order_by=updated_at&per_page=100&page=${pageNumber}`
|
||||
url: `${this.apiLink(cfg)}/issues?state=opened&order_by=updated_at&per_page=100&page=${pageNumber}`
|
||||
}, cfg).pipe(
|
||||
take(1),
|
||||
map((issues: GitlabOriginalIssue[]) => {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
taskChanges: {
|
||||
issueWasUpdated: true,
|
||||
issueLastUpdated: lastRemoteUpdate,
|
||||
title: `#${issue.number} ${issue.title}`,
|
||||
title: this._formatIssueTitle(issue.number, issue.title),
|
||||
},
|
||||
issue,
|
||||
};
|
||||
|
|
@ -108,6 +108,78 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
return null;
|
||||
}
|
||||
|
||||
async refreshIssues(
|
||||
tasks: Task[],
|
||||
isNotifySuccess: boolean = true,
|
||||
isNotifyNoUpdateRequired: boolean = false
|
||||
): Promise<{ task: Task, taskChanges: Partial<Task>, issue: GitlabIssue }[]> {
|
||||
// First sort the tasks by the issueId
|
||||
// because the API returns it in a desc order by issue iid(issueId)
|
||||
// so it makes the update check easier and faster
|
||||
tasks.sort((a, b) => +(b.issueId as string) - +(a.issueId as string));
|
||||
const projectId = tasks && tasks[0].projectId ? tasks[0].projectId : 0;
|
||||
if (!projectId) {
|
||||
throw new Error('No projectId');
|
||||
}
|
||||
|
||||
const cfg = await this._getCfgOnce$(projectId).toPromise();
|
||||
const issues: GitlabIssue[] = [];
|
||||
const paramsCount = 59; // Can't send more than 59 issue id For some reason it returns 502 bad gateway
|
||||
let ids;
|
||||
let i = 0;
|
||||
while (i < tasks.length) {
|
||||
ids = [];
|
||||
for (let j = 0; j < paramsCount && i < tasks.length ; j++, i++) {
|
||||
ids.push(tasks[i].issueId);
|
||||
}
|
||||
issues.push(...(await this._gitlabApiService.getByIds$(ids as string[], cfg).toPromise()));
|
||||
}
|
||||
|
||||
const updatedIssues: { task: Task, taskChanges: Partial<Task>, issue: GitlabIssue }[] = [];
|
||||
|
||||
for (i = 0; i < tasks.length; i++) {
|
||||
const issueUpdate: number = new Date(issues[i].updated_at).getTime();
|
||||
const commentsByOthers = (cfg.filterUsername && cfg.filterUsername.length > 1)
|
||||
? issues[i].comments.filter(comment => comment.author.username !== cfg.filterUsername)
|
||||
: issues[i].comments;
|
||||
|
||||
const updates: number[] = [
|
||||
...(commentsByOthers.map(comment => new Date(comment.created_at).getTime())),
|
||||
issueUpdate
|
||||
].sort();
|
||||
const lastRemoteUpdate = updates[updates.length - 1];
|
||||
const wasUpdated = lastRemoteUpdate > (tasks[i].issueLastUpdated || 0);
|
||||
|
||||
if (wasUpdated) {
|
||||
updatedIssues.push({
|
||||
task: tasks[i],
|
||||
taskChanges: {
|
||||
issueWasUpdated: true,
|
||||
issueLastUpdated: lastRemoteUpdate,
|
||||
title: this._formatIssueTitle(issues[i].number, issues[i].title),
|
||||
},
|
||||
issue: issues[i],
|
||||
});
|
||||
}
|
||||
|
||||
if (wasUpdated && isNotifySuccess) {
|
||||
this._snackService.open({
|
||||
ico: 'cloud_download',
|
||||
translateParams: {
|
||||
issueText: this._formatIssueTitleForSnack(issues[i].number, issues[i].title)
|
||||
},
|
||||
msg: T.F.GITLAB.S.ISSUE_UPDATE,
|
||||
});
|
||||
} else if (isNotifyNoUpdateRequired) {
|
||||
this._snackService.open({
|
||||
msg: T.F.GITLAB.S.ISSUE_NO_UPDATE_REQUIRED,
|
||||
ico: 'cloud_download',
|
||||
});
|
||||
}
|
||||
}
|
||||
return updatedIssues;
|
||||
}
|
||||
|
||||
getAddTaskData(issue: GitlabIssue): { title: string; additionalFields: Partial<IssueFieldsForTask> } {
|
||||
return {
|
||||
title: this._formatIssueTitle(issue.number, issue.title),
|
||||
|
|
|
|||
|
|
@ -38,17 +38,16 @@ export class GitlabIssueEffects {
|
|||
)
|
||||
.map(({task}: { cfg: GitlabCfg, task: TaskWithSubTasks }) => task)
|
||||
),
|
||||
tap((gitlabTasks: TaskWithSubTasks[]) => gitlabTasks.forEach((gitlabTask) => {
|
||||
tap((gitlabTasks: TaskWithSubTasks[]) => {
|
||||
if (gitlabTasks && gitlabTasks.length > 0) {
|
||||
this._snackService.open({
|
||||
msg: T.F.GITLAB.S.POLLING,
|
||||
svgIco: 'gitlab',
|
||||
isSpinner: true,
|
||||
});
|
||||
gitlabTasks.forEach((task) =>
|
||||
this._issueService.refreshIssue(task, true, false));
|
||||
this._issueService.refreshIssues(gitlabTasks, true, false);
|
||||
}
|
||||
})),
|
||||
}),
|
||||
);
|
||||
|
||||
private _pollTimer$: Observable<any> = timer(GITLAB_INITIAL_POLL_DELAY, GITLAB_POLL_INTERVAL);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue