Allow For Issues from multiple projects
This commit is contained in:
parent
ca28d83f65
commit
48e2b919f8
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
|
||||
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
|
||||
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:4200",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -38,7 +38,7 @@ export interface IssueServiceInterface {
|
|||
{
|
||||
task: Task;
|
||||
taskChanges: Partial<Task>;
|
||||
issue: IssueData;
|
||||
issue: IssueData | null;
|
||||
}[]
|
||||
>;
|
||||
|
||||
|
|
|
@ -29,36 +29,33 @@ import { GITLAB_TYPE, ISSUE_PROVIDER_HUMANIZED } from '../../../issue.const';
|
|||
export class GitlabApiService {
|
||||
constructor(private _snackService: SnackService, private _http: HttpClient) {}
|
||||
|
||||
getById$(id: number, cfg: GitlabCfg): Observable<GitlabIssue> {
|
||||
getById$(id: string, cfg: GitlabCfg): Observable<GitlabIssue> {
|
||||
return this._sendRequest$(
|
||||
{
|
||||
url: `${this.apiLink(cfg)}/issues/${id}`,
|
||||
url: `${this.apiLink(cfg, id)}`,
|
||||
},
|
||||
cfg,
|
||||
).pipe(
|
||||
mergeMap((issue: GitlabOriginalIssue) => {
|
||||
return this.getIssueWithComments$(mapGitlabIssue(issue), cfg);
|
||||
return this.getIssueWithComments$(mapGitlabIssue(issue, cfg), 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[]=`;
|
||||
}
|
||||
}
|
||||
getByIds$(project: string, ids: string[], cfg: GitlabCfg): Observable<GitlabIssue[]> {
|
||||
const queryParams = 'iids[]=' + ids.join('&iids[]=');
|
||||
|
||||
return this._sendRequest$(
|
||||
{
|
||||
url: `${this.apiLink(cfg)}/issues?${queryParams}&per_page=100`,
|
||||
url: `${this.apiLink(
|
||||
cfg,
|
||||
null,
|
||||
)}/projects/${project}/issues?${queryParams}&scope=${cfg.scope}&per_page=100`,
|
||||
},
|
||||
cfg,
|
||||
).pipe(
|
||||
map((issues: GitlabOriginalIssue[]) => {
|
||||
return issues ? issues.map(mapGitlabIssue) : [];
|
||||
return issues ? issues.map((issue) => mapGitlabIssue(issue, cfg)) : [];
|
||||
}),
|
||||
mergeMap((issues: GitlabIssue[]) => {
|
||||
if (issues && issues.length) {
|
||||
|
@ -93,12 +90,14 @@ export class GitlabApiService {
|
|||
}
|
||||
return this._sendRequest$(
|
||||
{
|
||||
url: `${this.apiLink(cfg)}/issues?search=${searchText}&order_by=updated_at`,
|
||||
url: `${this.apiLink(cfg, null)}/issues?search=${searchText}&scope=${
|
||||
cfg.scope
|
||||
}&order_by=updated_at`,
|
||||
},
|
||||
cfg,
|
||||
).pipe(
|
||||
map((issues: GitlabOriginalIssue[]) => {
|
||||
return issues ? issues.map(mapGitlabIssue) : [];
|
||||
return issues ? issues.map((issue) => mapGitlabIssue(issue, cfg)) : [];
|
||||
}),
|
||||
mergeMap((issues: GitlabIssue[]) => {
|
||||
if (issues && issues.length) {
|
||||
|
@ -137,19 +136,68 @@ export class GitlabApiService {
|
|||
{
|
||||
url: `${this.apiLink(
|
||||
cfg,
|
||||
)}/issues?state=opened&order_by=updated_at&per_page=100&page=${pageNumber}`,
|
||||
null,
|
||||
)}/issues?state=opened&order_by=updated_at&per_page=100&scope=${
|
||||
cfg.scope
|
||||
}&page=${pageNumber}`,
|
||||
},
|
||||
cfg,
|
||||
).pipe(
|
||||
take(1),
|
||||
map((issues: GitlabOriginalIssue[]) => {
|
||||
return issues ? issues.map(mapGitlabIssue) : [];
|
||||
return issues ? issues.map((issue) => mapGitlabIssue(issue, cfg)) : [];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
getFullIssueRef$(issue: string | number, projectConfig: GitlabCfg): string {
|
||||
if (this._getPartsFromIssue$(issue).length === 2) {
|
||||
return issue.toString();
|
||||
} else {
|
||||
return (
|
||||
this.getProjectFromIssue$(issue, projectConfig) +
|
||||
'#' +
|
||||
this._getIidFromIssue$(issue)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getProjectFromIssue$(issue: string | number | null, projectConfig: GitlabCfg): string {
|
||||
const parts: string[] = this._getPartsFromIssue$(issue);
|
||||
if (parts.length === 2) {
|
||||
return parts[0];
|
||||
}
|
||||
|
||||
const projectURL: string = projectConfig.project ? projectConfig.project : '';
|
||||
|
||||
const projectPath = projectURL.match(GITLAB_PROJECT_REGEX);
|
||||
if (!projectPath) {
|
||||
throwError('Gitlab Project URL');
|
||||
}
|
||||
return projectURL;
|
||||
}
|
||||
|
||||
private _getIidFromIssue$(issue: string | number): string {
|
||||
const parts: string[] = this._getPartsFromIssue$(issue);
|
||||
if (parts.length === 2) {
|
||||
return parts[1];
|
||||
} else {
|
||||
return parts[0];
|
||||
}
|
||||
}
|
||||
|
||||
private _getPartsFromIssue$(issue: string | number | null): string[] {
|
||||
if (typeof issue === 'string') {
|
||||
return issue.split('#');
|
||||
} else if (typeof issue == 'number') {
|
||||
return [issue.toString()];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private _getIssueComments$(
|
||||
issueid: number,
|
||||
issueid: number | string,
|
||||
pageNumber: number,
|
||||
cfg: GitlabCfg,
|
||||
): Observable<GitlabOriginalComment[]> {
|
||||
|
@ -158,9 +206,7 @@ export class GitlabApiService {
|
|||
}
|
||||
return this._sendRequest$(
|
||||
{
|
||||
url: `${this.apiLink(
|
||||
cfg,
|
||||
)}/issues/${issueid}/notes?per_page=100&page=${pageNumber}`,
|
||||
url: `${this.apiLink(cfg, issueid)}/notes?per_page=100&page=${pageNumber}`,
|
||||
},
|
||||
cfg,
|
||||
).pipe(
|
||||
|
@ -259,25 +305,36 @@ export class GitlabApiService {
|
|||
return throwError({ [HANDLED_ERROR_PROP_STR]: 'Gitlab: Api request failed.' });
|
||||
}
|
||||
|
||||
private apiLink(projectConfig: GitlabCfg): string {
|
||||
private apiLink(projectConfig: GitlabCfg, issueId: string | number | null): string {
|
||||
let apiURL: string = '';
|
||||
let projectURL: string = projectConfig.project ? projectConfig.project : '';
|
||||
|
||||
if (projectConfig.gitlabBaseUrl) {
|
||||
const fixedUrl = projectConfig.gitlabBaseUrl.match(/.*\/$/)
|
||||
? projectConfig.gitlabBaseUrl
|
||||
: `${projectConfig.gitlabBaseUrl}/`;
|
||||
apiURL = fixedUrl + 'api/v4/projects/';
|
||||
apiURL = fixedUrl + 'api/v4/';
|
||||
} else {
|
||||
apiURL = GITLAB_API_BASE_URL + '/';
|
||||
}
|
||||
const projectPath = projectURL.match(GITLAB_PROJECT_REGEX);
|
||||
if (projectPath) {
|
||||
projectURL = projectURL.replace(/\//gi, '%2F');
|
||||
|
||||
const projectURL: string = this.getProjectFromIssue$(issueId, projectConfig).replace(
|
||||
/\//gi,
|
||||
'%2F',
|
||||
);
|
||||
|
||||
if (issueId) {
|
||||
apiURL += 'projects/' + projectURL + '/issues/' + this._getIidFromIssue$(issueId);
|
||||
} else {
|
||||
// Should never enter here
|
||||
throwError('Gitlab Project URL');
|
||||
switch (projectConfig.source) {
|
||||
case 'project':
|
||||
apiURL += 'projects/' + projectURL;
|
||||
break;
|
||||
case 'group':
|
||||
apiURL += 'groups/' + projectURL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
apiURL += projectURL;
|
||||
|
||||
return apiURL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,25 +43,23 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
return isGitlabEnabled(cfg);
|
||||
}
|
||||
|
||||
issueLink$(issueId: number, projectId: string): Observable<string> {
|
||||
issueLink$(issueId: string, projectId: string): Observable<string> {
|
||||
return this._getCfgOnce$(projectId).pipe(
|
||||
map((cfg) => {
|
||||
const project: string = this._gitlabApiService.getProjectFromIssue$(issueId, cfg);
|
||||
if (cfg.gitlabBaseUrl) {
|
||||
const fixedUrl = cfg.gitlabBaseUrl.match(/.*\/$/)
|
||||
? cfg.gitlabBaseUrl
|
||||
: `${cfg.gitlabBaseUrl}/`;
|
||||
return `${fixedUrl}${cfg.project}/issues/${issueId}`;
|
||||
return `${fixedUrl}${project}/issues/${issueId}`;
|
||||
} else {
|
||||
return `${GITLAB_BASE_URL}${cfg.project?.replace(
|
||||
/%2F/g,
|
||||
'/',
|
||||
)}/issues/${issueId}`;
|
||||
return `${GITLAB_BASE_URL}${project}/issues/${issueId}`;
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
getById$(issueId: number, projectId: string): Observable<GitlabIssue> {
|
||||
getById$(issueId: string, projectId: string): Observable<GitlabIssue> {
|
||||
return this._getCfgOnce$(projectId).pipe(
|
||||
concatMap((gitlabCfg) => this._gitlabApiService.getById$(issueId, gitlabCfg)),
|
||||
);
|
||||
|
@ -92,7 +90,9 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
}
|
||||
|
||||
const cfg = await this._getCfgOnce$(task.projectId).toPromise();
|
||||
const issue = await this._gitlabApiService.getById$(+task.issueId, cfg).toPromise();
|
||||
const fullIssueRef = this._gitlabApiService.getFullIssueRef$(task.issueId, cfg);
|
||||
const idFormatChanged = task.issueId !== fullIssueRef;
|
||||
const issue = await this._gitlabApiService.getById$(fullIssueRef, cfg).toPromise();
|
||||
|
||||
const issueUpdate: number = new Date(issue.updated_at).getTime();
|
||||
const commentsByOthers =
|
||||
|
@ -111,14 +111,14 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
|
||||
const wasUpdated = lastRemoteUpdate > (task.issueLastUpdated || 0);
|
||||
|
||||
if (wasUpdated) {
|
||||
if (wasUpdated || idFormatChanged) {
|
||||
return {
|
||||
taskChanges: {
|
||||
...this.getAddTaskData(issue),
|
||||
issueWasUpdated: true,
|
||||
},
|
||||
issue,
|
||||
issueTitle: this._formatIssueTitleForSnack(issue.number, issue.title),
|
||||
issueTitle: this._formatIssueTitleForSnack(issue),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
|
@ -126,61 +126,89 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
|
||||
async getFreshDataForIssueTasks(
|
||||
tasks: Task[],
|
||||
): 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));
|
||||
): Promise<{ task: Task; taskChanges: Partial<Task>; issue: GitlabIssue | null }[]> {
|
||||
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 issues = new Map<string, GitlabIssue>();
|
||||
const paramsCount = 59; // Can't send more than 59 issue id For some reason it returns 502 bad gateway
|
||||
let ids;
|
||||
const iidsByProject = new Map<string, string[]>();
|
||||
let i = 0;
|
||||
while (i < tasks.length) {
|
||||
ids = [];
|
||||
for (let j = 0; j < paramsCount && i < tasks.length; j++, i++) {
|
||||
ids.push(tasks[i].issueId);
|
||||
|
||||
for (const task of tasks) {
|
||||
if (!task.issueId) {
|
||||
continue;
|
||||
}
|
||||
issues.push(
|
||||
...(await this._gitlabApiService.getByIds$(ids as string[], cfg).toPromise()),
|
||||
);
|
||||
const project = this._gitlabApiService.getProjectFromIssue$(task.issueId, cfg);
|
||||
if (!iidsByProject.has(project)) {
|
||||
iidsByProject.set(project, []);
|
||||
}
|
||||
iidsByProject.get(project)?.push(task.issueId as string);
|
||||
}
|
||||
|
||||
iidsByProject.forEach(async (allIds, project) => {
|
||||
for (i = 0; i < allIds.length; i += paramsCount) {
|
||||
(
|
||||
await this._gitlabApiService
|
||||
.getByIds$(project, allIds.slice(i, i + paramsCount), cfg)
|
||||
.toPromise()
|
||||
).forEach((found) => {
|
||||
issues.set(found.id as string, found);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const updatedIssues: {
|
||||
task: Task;
|
||||
taskChanges: Partial<Task>;
|
||||
issue: GitlabIssue;
|
||||
issue: GitlabIssue | null;
|
||||
}[] = [];
|
||||
|
||||
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;
|
||||
for (const task of tasks) {
|
||||
if (!task.issueId) {
|
||||
continue;
|
||||
}
|
||||
let idFormatChanged = false;
|
||||
const fullIssueRef = this._gitlabApiService.getFullIssueRef$(task.issueId, cfg);
|
||||
idFormatChanged = task.issueId !== fullIssueRef;
|
||||
const issue = issues.get(fullIssueRef);
|
||||
if (issue) {
|
||||
const issueUpdate: number = new Date(issue.updated_at).getTime();
|
||||
const commentsByOthers =
|
||||
cfg.filterUsername && cfg.filterUsername.length > 1
|
||||
? issue.comments.filter(
|
||||
(comment) => comment.author.username !== cfg.filterUsername,
|
||||
)
|
||||
: issue.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) {
|
||||
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 || idFormatChanged) {
|
||||
updatedIssues.push({
|
||||
task,
|
||||
taskChanges: {
|
||||
...this.getAddTaskData(issue),
|
||||
issueWasUpdated: true,
|
||||
},
|
||||
issue,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
updatedIssues.push({
|
||||
task: tasks[i],
|
||||
task,
|
||||
taskChanges: {
|
||||
...this.getAddTaskData(issues[i]),
|
||||
issueWasUpdated: true,
|
||||
issueId: null,
|
||||
issueType: null,
|
||||
},
|
||||
issue: issues[i],
|
||||
issue: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -189,10 +217,11 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
|
||||
getAddTaskData(issue: GitlabIssue): Partial<Task> & { title: string } {
|
||||
return {
|
||||
title: this._formatIssueTitle(issue.number, issue.title),
|
||||
title: this._formatIssueTitle(issue),
|
||||
issuePoints: issue.weight,
|
||||
issueWasUpdated: false,
|
||||
issueLastUpdated: new Date(issue.updated_at).getTime(),
|
||||
issueId: issue.id as string,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -204,12 +233,12 @@ export class GitlabCommonInterfacesService implements IssueServiceInterface {
|
|||
return await this._gitlabApiService.getProjectIssues$(1, cfg).toPromise();
|
||||
}
|
||||
|
||||
private _formatIssueTitle(id: number, title: string): string {
|
||||
return `#${id} ${title}`;
|
||||
private _formatIssueTitle(issue: GitlabIssue): string {
|
||||
return `#${issue.number} ${issue.title}`;
|
||||
}
|
||||
|
||||
private _formatIssueTitleForSnack(id: number, title: string): string {
|
||||
return `${truncate(this._formatIssueTitle(id, title))}`;
|
||||
private _formatIssueTitleForSnack(issue: GitlabIssue): string {
|
||||
return `${truncate(this._formatIssueTitle(issue))}`;
|
||||
}
|
||||
|
||||
private _getCfgOnce$(projectId: string): Observable<GitlabCfg> {
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import { GitlabIssue } from './gitlab-issue.model';
|
||||
import { GitlabOriginalIssue } from '../gitlab-api/gitlab-api-responses';
|
||||
import { IssueProviderKey, SearchResultItem } from '../../../issue.model';
|
||||
import { GitlabCfg } from '../gitlab';
|
||||
|
||||
export const mapGitlabIssue = (issue: GitlabOriginalIssue): GitlabIssue => {
|
||||
export const mapGitlabIssue = (
|
||||
issue: GitlabOriginalIssue,
|
||||
cfg: GitlabCfg,
|
||||
): GitlabIssue => {
|
||||
return {
|
||||
html_url: issue.web_url,
|
||||
// eslint-disable-next-line id-blacklist
|
||||
|
@ -27,7 +31,8 @@ export const mapGitlabIssue = (issue: GitlabOriginalIssue): GitlabIssue => {
|
|||
comments: [],
|
||||
url: issue.web_url,
|
||||
// NOTE: we use the issue number as id as well, as it there is not much to be done with the id with the api
|
||||
id: issue.iid,
|
||||
// when we can get issues from multiple projects we use full refence as id
|
||||
id: issue.references.full,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ export type GitlabIssue = Readonly<{
|
|||
comments: GitlabComment[];
|
||||
url: string;
|
||||
// NOTE: we use the issue number as id as well, as it there is not much to be done with the id with the api
|
||||
id: number;
|
||||
id: number | string;
|
||||
|
||||
// according to the docs: "Users on GitLab Starter, Bronze, or higher will also see the weight parameter"
|
||||
weight?: number;
|
||||
|
|
|
@ -15,6 +15,8 @@ export const DEFAULT_GITLAB_CFG: GitlabCfg = {
|
|||
isAutoPoll: false,
|
||||
isAutoAddToBacklog: false,
|
||||
filterUsername: null,
|
||||
scope: 'created-by-me',
|
||||
source: 'project',
|
||||
};
|
||||
|
||||
// NOTE: we need a high limit because git has low usage limits :(
|
||||
|
@ -25,7 +27,7 @@ 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/projects`;
|
||||
export const GITLAB_API_BASE_URL = `${GITLAB_BASE_URL}api/v4`;
|
||||
|
||||
export const GITLAB_PROJECT_REGEX =
|
||||
/(^[1-9][0-9]*$)|((\w-?|\.-?)+((\/|%2F)(\w-?|\.-?)+)+$)/i;
|
||||
|
@ -41,6 +43,19 @@ export const GITLAB_CONFIG_FORM: LimitedFormlyFieldConfig<GitlabCfg>[] = [
|
|||
/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'source',
|
||||
type: 'select',
|
||||
defaultValue: 'project',
|
||||
templateOptions: {
|
||||
label: T.F.GITLAB.FORM.SOURCE,
|
||||
options: [
|
||||
{ value: 'project', label: T.F.GITLAB.FORM.SOURCE_PROJECT },
|
||||
{ value: 'group', label: T.F.GITLAB.FORM.SOURCE_GROUP },
|
||||
{ value: 'global', label: T.F.GITLAB.FORM.SOURCE_GLOBAL },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'project',
|
||||
type: 'input',
|
||||
|
@ -95,6 +110,19 @@ export const GITLAB_CONFIG_FORM: LimitedFormlyFieldConfig<GitlabCfg>[] = [
|
|||
label: T.F.GITLAB.FORM.FILTER_USER,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'scope',
|
||||
type: 'select',
|
||||
defaultValue: 'created-by-me',
|
||||
templateOptions: {
|
||||
label: T.F.GITLAB.FORM.SCOPE,
|
||||
options: [
|
||||
{ value: 'all', label: T.F.GITLAB.FORM.SCOPE_ALL },
|
||||
{ value: 'created-by-me', label: T.F.GITLAB.FORM.SCOPE_CREATED },
|
||||
{ value: 'assigned-to-me', label: T.F.GITLAB.FORM.SCOPE_ASSIGNED },
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const GITLAB_CONFIG_FORM_SECTION: ConfigFormSection<GitlabCfg> = {
|
||||
|
|
|
@ -4,6 +4,8 @@ export interface GitlabCfg {
|
|||
isAutoPoll: boolean;
|
||||
filterUsername: string | null;
|
||||
gitlabBaseUrl: string | null | undefined;
|
||||
source: string | null;
|
||||
project: string | null;
|
||||
token: string | null;
|
||||
scope: string | null;
|
||||
}
|
||||
|
|
|
@ -167,6 +167,14 @@ const T = {
|
|||
IS_SEARCH_ISSUES_FROM_GITLAB: 'F.GITLAB.FORM.IS_SEARCH_ISSUES_FROM_GITLAB',
|
||||
PROJECT: 'F.GITLAB.FORM.PROJECT',
|
||||
TOKEN: 'F.GITLAB.FORM.TOKEN',
|
||||
SCOPE: 'F.GITLAB.FORM.SCOPE',
|
||||
SCOPE_ALL: 'F.GITLAB.FORM.SCOPE_ALL',
|
||||
SCOPE_ASSIGNED: 'F.GITLAB.FORM.SCOPE_ASSIGNED',
|
||||
SCOPE_CREATED: 'F.GITLAB.FORM.SCOPE_CREATED',
|
||||
SOURCE: 'F.GITLAB.FORM.SOURCE',
|
||||
SOURCE_GLOBAL: 'F.GITLAB.FORM.SOURCE_GLOBAL',
|
||||
SOURCE_PROJECT: 'F.GITLAB.FORM.SOURCE_PROJECT',
|
||||
SOURCE_GROUP: 'F.GITLAB.FORM.SOURCE_GROUP',
|
||||
},
|
||||
FORM_SECTION: {
|
||||
HELP: 'F.GITLAB.FORM_SECTION.HELP',
|
||||
|
|
|
@ -165,8 +165,16 @@
|
|||
"IS_AUTO_ADD_TO_BACKLOG": "Automatically add unresolved issues from GitLab to backlog",
|
||||
"IS_AUTO_POLL": "Automatically poll imported git issues for changes",
|
||||
"IS_SEARCH_ISSUES_FROM_GITLAB": "Show issues from git as suggestions when adding new tasks",
|
||||
"PROJECT": "project ID or user name/project",
|
||||
"TOKEN": "Access Token"
|
||||
"PROJECT": "(default) project ID or user name/project",
|
||||
"TOKEN": "Access Token",
|
||||
"SCOPE": "Scope",
|
||||
"SCOPE_ALL": "All",
|
||||
"SCOPE_ASSIGNED": "Assigned to me",
|
||||
"SCOPE_CREATED": "Created by me",
|
||||
"SOURCE": "Source",
|
||||
"SOURCE_GLOBAL": "All",
|
||||
"SOURCE_PROJECT": "Project",
|
||||
"SOURCE_GROUP": "Group"
|
||||
},
|
||||
"FORM_SECTION": {
|
||||
"HELP": "<p>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.</p> <p>In addition you can automatically add and sync all open issues to your task backlog.</p>",
|
||||
|
|
Loading…
Reference in New Issue
Block a user