diff --git a/src/app/features/issue/providers/gitlab/gitlab-api/gitlab-api.service.ts b/src/app/features/issue/providers/gitlab/gitlab-api/gitlab-api.service.ts index 8786d8c0242..4cbd41f5789 100644 --- a/src/app/features/issue/providers/gitlab/gitlab-api/gitlab-api.service.ts +++ b/src/app/features/issue/providers/gitlab/gitlab-api/gitlab-api.service.ts @@ -12,7 +12,7 @@ import { SnackService } from 'src/app/core/snack/snack.service'; import { GitlabCfg } from '../gitlab.model'; import { GitlabOriginalComment, GitlabOriginalIssue } from './gitlab-api-responses'; -import { GITLAB_API_BASE_URL } from '../gitlab.const'; +import { GITLAB_BASE_URL } from '../gitlab.const'; import { T } from 'src/app/t.const'; import { catchError, @@ -58,6 +58,11 @@ export class GitlabApiService { ); } + getIssuelink$(id: string, cfg: GitlabCfg): string { + const { project, projectIssueId } = getPartsFromGitlabIssueId(id); + return `${this._baseLink(cfg)}${project}/issues/${projectIssueId}`; + } + private getScopeParam(cfg: GitlabCfg): string { if (cfg.scope) { return `&scope=${cfg.scope}`; @@ -80,7 +85,7 @@ export class GitlabApiService { // // const PARAMS_COUNT = 59; // Can't send more than 59 issue id For some reason it returns 502 bad gateway // return this._sendIssuePaginatedRequest$( // { - // url: `${this._apiLink(cfg)}/issues?${queryParams}${this.getScopeParam( + // url: `${this._autoScopedApiLink(cfg)}/issues?${queryParams}${this.getScopeParam( // cfg, // )}${this.getCustomFilterParam(cfg)}`, // }, @@ -119,7 +124,7 @@ export class GitlabApiService { } return this._sendIssuePaginatedRequest$( { - url: `${this._apiLink(cfg)}/issues?search=${searchText}${this.getScopeParam( + url: `${this._autoScopedApiLink(cfg)}/issues?search=${searchText}${this.getScopeParam( cfg, )}&order_by=updated_at${this.getCustomFilterParam(cfg)}`, }, @@ -143,7 +148,7 @@ export class GitlabApiService { getProjectIssues$(cfg: GitlabCfg): Observable { return this._sendIssuePaginatedRequest$( { - url: `${this._apiLink( + url: `${this._autoScopedApiLink( cfg, )}/issues?state=opened&order_by=updated_at&${this.getScopeParam( cfg, @@ -166,11 +171,9 @@ export class GitlabApiService { total_time_spent: null | number; }*/ - const { projectIssueId } = getPartsFromGitlabIssueId(issueId); - return this._sendRawRequest$( { - url: `${this._apiLink(cfg)}/issues/${projectIssueId}/add_spent_time`, + url: `${this._issueApiLink(cfg, issueId)}/add_spent_time`, method: 'POST', data: { duration: duration, @@ -190,10 +193,9 @@ export class GitlabApiService { time_estimate: null | number; total_time_spent: null | number; }> { - const { projectIssueId } = getPartsFromGitlabIssueId(issueId); return this._sendRawRequest$( { - url: `${this._apiLink(cfg)}/issues/${projectIssueId}/time_stats`, + url: `${this._issueApiLink(cfg, issueId)}/time_stats`, }, cfg, ).pipe(map((res) => (res as any).body)); @@ -326,24 +328,46 @@ export class GitlabApiService { private _issueApiLink(cfg: GitlabCfg, issueId: string): string { console.log(issueId); - const { projectIssueId } = getPartsFromGitlabIssueId(issueId); - return `${this._apiLink(cfg)}/issues/${projectIssueId}`; + const { project, projectIssueId } = getPartsFromGitlabIssueId(issueId); + return `${this._baseApiLink(cfg)}/${this._projectUrl(project)}/issues/${projectIssueId}`; } - private _apiLink(cfg: GitlabCfg): string { - let apiURL: string = ''; + private _autoScopedApiLink(cfg: GitlabCfg): string { + let apiURL: string = this._baseApiLink(cfg); + + if (cfg.search_scope == 'group') { + const groupURL = assertTruthy(cfg.project) + .toString() + .split(/\//gi) + .slice(0, -1) + .join('%2F'); + apiURL += 'groups/' + groupURL; + } else if (cfg.search_scope == 'project' || cfg.search_scope === null) { + apiURL += this._projectUrl(cfg.project); + } + + return apiURL; + } + + private _projectUrl(project: string): string { + const projectURL = assertTruthy(project).toString().replace(/\//gi, '%2F'); + return 'projects/' + projectURL; + } + + private _baseLink(cfg: GitlabCfg): string { + let baseURL: string = GITLAB_BASE_URL; if (cfg.gitlabBaseUrl) { const fixedUrl = cfg.gitlabBaseUrl.match(/.*\/$/) ? cfg.gitlabBaseUrl : `${cfg.gitlabBaseUrl}/`; - apiURL = fixedUrl + 'api/v4/'; - } else { - apiURL = GITLAB_API_BASE_URL + '/'; + baseURL = fixedUrl; } - const projectURL = assertTruthy(cfg.project).toString().replace(/\//gi, '%2F'); - apiURL += 'projects/' + projectURL; - return apiURL; + return baseURL; + } + + private _baseApiLink(cfg: GitlabCfg): string { + return this._baseLink(cfg) + 'api/v4/'; } } diff --git a/src/app/features/issue/providers/gitlab/gitlab-common-interfaces.service.ts b/src/app/features/issue/providers/gitlab/gitlab-common-interfaces.service.ts index 8574956232a..70169adf994 100644 --- a/src/app/features/issue/providers/gitlab/gitlab-common-interfaces.service.ts +++ b/src/app/features/issue/providers/gitlab/gitlab-common-interfaces.service.ts @@ -8,11 +8,7 @@ import { IssueData, IssueProviderGitlab, SearchResultItem } from '../../issue.mo import { GitlabCfg } from './gitlab.model'; import { GitlabIssue } from './gitlab-issue/gitlab-issue.model'; import { truncate } from '../../../../util/truncate'; -import { - GITLAB_BASE_URL, - GITLAB_INITIAL_POLL_DELAY, - GITLAB_POLL_INTERVAL, -} from './gitlab.const'; +import { GITLAB_INITIAL_POLL_DELAY, GITLAB_POLL_INTERVAL } from './gitlab.const'; import { isGitlabEnabled } from './is-gitlab-enabled'; import { IssueProviderService } from '../../issue-provider.service'; @@ -39,15 +35,7 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface { issueLink$(issueId: string, issueProviderId: string): Observable { return this._getCfgOnce$(issueProviderId).pipe( map((cfg) => { - const project: string = cfg.project; - if (cfg.gitlabBaseUrl) { - const fixedUrl = cfg.gitlabBaseUrl.match(/.*\/$/) - ? cfg.gitlabBaseUrl - : `${cfg.gitlabBaseUrl}/`; - return `${fixedUrl}${project}/issues/${issueId}`; - } else { - return `${GITLAB_BASE_URL}${project}/issues/${issueId}`; - } + return this._gitlabApiService.getIssuelink$(issueId, cfg); }), ); } diff --git a/src/app/features/issue/providers/gitlab/gitlab.const.ts b/src/app/features/issue/providers/gitlab/gitlab.const.ts index 2c1c7869ad5..425a010b357 100644 --- a/src/app/features/issue/providers/gitlab/gitlab.const.ts +++ b/src/app/features/issue/providers/gitlab/gitlab.const.ts @@ -21,6 +21,7 @@ export const DEFAULT_GITLAB_CFG: GitlabCfg = { scope: 'all', filter: null, isEnableTimeTracking: false, + search_scope: 'project', }; // NOTE: we need a high limit because git has low usage limits :( @@ -30,8 +31,6 @@ export const GITLAB_INITIAL_POLL_DELAY = GITHUB_INITIAL_POLL_DELAY + 8000; // export const GITLAB_POLL_INTERVAL = 15 * 1000; export const GITLAB_BASE_URL = 'https://gitlab.com/'; -export const GITLAB_API_BASE_URL = `${GITLAB_BASE_URL}api/v4`; - export const GITLAB_PROJECT_REGEX = /(^[1-9][0-9]*$)|((\/|%2F|\w-?|\.-?)+$)/i; export const GITLAB_CONFIG_FORM: LimitedFormlyFieldConfig[] = [ @@ -143,6 +142,20 @@ export const GITLAB_CONFIG_FORM: LimitedFormlyFieldConfig[] description: T.F.GITLAB.FORM.SUBMIT_TIMELOGS_DESCRIPTION, }, }, + { + key: 'search_scope', + type: 'select', + defaultValue: 'project', + templateOptions: { + required: true, + label: T.F.GITLAB.FORM.SEARCH_SCOPE, + options: [ + { value: 'project', label: T.F.GITLAB.FORM.SEARCH_SCOPE_PROJECT }, + { value: 'group', label: T.F.GITLAB.FORM.SEARCH_SCOPE_GROUP }, + { value: 'instance', label: T.F.GITLAB.FORM.SEARCH_SCOPE_INSTANCE }, + ], + }, + }, ], }, ]; diff --git a/src/app/features/issue/providers/gitlab/gitlab.model.ts b/src/app/features/issue/providers/gitlab/gitlab.model.ts index 6313786065f..56ad3fa196e 100644 --- a/src/app/features/issue/providers/gitlab/gitlab.model.ts +++ b/src/app/features/issue/providers/gitlab/gitlab.model.ts @@ -8,4 +8,5 @@ export interface GitlabCfg extends BaseIssueProviderCfg { scope: string | null; filter: string | null; isEnableTimeTracking: boolean; + search_scope: string | null; } diff --git a/src/app/t.const.ts b/src/app/t.const.ts index 572b55518af..b89440573b5 100644 --- a/src/app/t.const.ts +++ b/src/app/t.const.ts @@ -284,6 +284,10 @@ const T = { SUBMIT_TIMELOGS: 'F.GITLAB.FORM.SUBMIT_TIMELOGS', SUBMIT_TIMELOGS_DESCRIPTION: 'F.GITLAB.FORM.SUBMIT_TIMELOGS_DESCRIPTION', TOKEN: 'F.GITLAB.FORM.TOKEN', + SEARCH_SCOPE: 'F.GITLAB.FORM.SEARCH_SCOPE', + SEARCH_SCOPE_PROJECT: 'F.GITLAB.FORM.SEARCH_SCOPE_PROJECT', + SEARCH_SCOPE_GROUP: 'F.GITLAB.FORM.SEARCH_SCOPE_GROUP', + SEARCH_SCOPE_INSTANCE: 'F.GITLAB.FORM.SEARCH_SCOPE_INSTANCE', }, FORM_SECTION: { HELP: 'F.GITLAB.FORM_SECTION.HELP', diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 2a5a41b037e..9ccaab69951 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -281,7 +281,11 @@ "SOURCE_PROJECT": "Project", "SUBMIT_TIMELOGS": "Submit timelogs to Gitlab", "SUBMIT_TIMELOGS_DESCRIPTION": "Show Time Tracking Dialog after clicking on finish day", - "TOKEN": "Access Token" + "TOKEN": "Access Token", + "SEARCH_SCOPE": "Search Scope", + "SEARCH_SCOPE_INSTANCE": "Instance", + "SEARCH_SCOPE_GROUP": "Group", + "SEARCH_SCOPE_PROJECT": "Project" }, "FORM_SECTION": { "HELP": "

Here you can configure SuperProductivity to list open GitLab (either its the online version or a self-hosted instance) issues for a specific project in the task creation panel in the daily planning view. They will be listed as suggestions and will provide a link to the issue as well as more information about it.

In addition you can automatically import all open issues.

",