import merge from 'lodash.merge' import JiraApi from './jira-api' import { notification, Typography } from 'antd' import React from 'react' import cookie from 'js-cookie' import url from 'url' import omitNil from 'omit-nil' /** * /rest/greenhopper/1.0/sprint/picker?query= * 获取 Sprint suggest * * /rest/greenhopper/1.0/epics?searchQuery=&projectKey=YFDTR&maxResults=100&hideDone=true * 获取 epic link suggest */ export default class JiraApiBrowser extends JiraApi { constructor(opts: Partial[0]>) { if (!opts.baseURL) { opts.baseURL = getJiraRestURL() } if (!opts.user) { opts.user = JIRA.Users.LoggedInUser.userName() } // @ts-ignore super(opts) this.axios.interceptors.response.use((res) => { if (res.data) { // res.data. } return res }) } async search(jql) { return this.request({ url: `/search`, params: { jql } }) } async setAssignees(dataList) { return Promise.all( dataList.map(({ issueIdOrKey, assignee }) => { return this.setAssignee(issueIdOrKey, assignee) }) ) } async setAssignee(issueIdOrKey, assignee) { return this.request({ method: 'put', url: `/issue/${issueIdOrKey}/assignee`, data: assignee }) } async getBacklogData(rapidViewId: number, selectedProjectKey: string) { return this.request({ method: 'get', baseURL: url.format({ host: url.parse(this.axios.defaults.baseURL || '').host, pathname: '' }), url: '/rest/greenhopper/1.0/xboard/plan/backlog/data.json', params: { rapidViewId, selectedProjectKey } }) } async querySuggestEpics({ maxResults = 20, hideDone = true, searchQuery, projectKey = JIRA.API.Projects.getCurrentProjectKey() }: { maxResults?: number hideDone?: boolean searchQuery?: string projectKey?: string }) { return this.request({ method: 'get', baseURL: url.format({ host: url.parse(this.axios.defaults.baseURL || '').host, pathname: '' }), url: '/rest/greenhopper/latest/epics', params: { searchQuery, projectKey, maxResults: maxResults, hideDone } }) } async updateIssue( issue: string, { estimate }: { estimate?: number }, { toast = true }: { toast?: boolean } = {} ) { const token = cookie.get('atlassian.xsrf.token') const data = new FormData() if (estimate != null) { data.append('customfield_10002', estimate as any) } if (token) { data.append('atl_token', token) data.append('rapidViewId', '939') } data.append('issueId', issue) // @ts-ignore data.append('singleFieldEdit', true) // @ts-ignore data.append('skipScreenCheck', true) data.append('fieldsToForcePresent', 'customfield_10002') const res = await this.request({ method: 'post', baseURL: '', url: '/secure/DetailsViewAjaxIssueAction.jspa?decorator=none', data }) // this._toastErrors(res.data.errors, { message: 'Failed' }) || this._toastErrors(res.data.errorMessages, { message: 'Failed' }) if (toast && res.data.issue) { notification.success({ message: 'Issue 更新成功' }) } else if (toast) { notification.error({ message: 'Issue 更新失败' }) } } async queryIssue(issue: string) { const res = await this.request({ method: 'get', url: '/issue/' + issue }) this._toastErrors(res.data.errors) || this._toastErrors(res.data.errorMessages) return res } queryComponents() { return this.axios .request({ method: 'GET', url: `/project/${JIRA.API.Projects.getCurrentProjectKey()}/components` }) .then((res) => res.data) } async querySuggestSprints({ query }: { query?: string }) { return this.request({ method: 'get', baseURL: url.format({ host: url.parse(this.axios.defaults.baseURL || '').host, pathname: '' }), url: '/rest/greenhopper/latest/sprint/picker', params: { query } }) } async querySuggestUsers({ showAvatar = true, query }: { showAvatar?: boolean; query?: string }) { return this.request({ method: 'get', url: '/user/picker', params: { query, showAvatar } }) } async querySuggestLabels(query) { return this.request({ method: 'get', baseURL: url.format({ host: url.parse(this.axios.defaults.baseURL || '').host, pathname: '' }), url: '/rest/api/1.0/labels/suggest', params: { query } }) } async queryFields() { const response = await this.request({ method: 'get', baseURL: url.format({ host: url.parse(this.axios.defaults.baseURL || '').host, pathname: '' }), url: '/secure/QuickCreateIssue!default.jspa?decorator=none', params: {} }) if (response.data) { let list = (response.data.fields || []).slice() if (response.data.sortedTabs?.length) { response.data.sortedTabs.forEach((tabs) => { list = list.concat(tabs.fields) }) } console.log('list', list) return list } return [] } private _createIssueReqBody({ estimate, priority, epicLink, issuetype, sprint, assignee, labels, dod, reporter, ...data }: { estimate?: number reporter?: string assignee?: string sprint?: any dod?: any epicLink?: any summary?: string description?: string priority?: string [prop: string]: any } = {}) { const config = omitNil( merge( { customfield_10002: estimate, customfield_10004: sprint, customfield_10506: dod != null ? { id: dod } : null, customfield_10005: epicLink, project: { key: JIRA.API.Projects.getCurrentProjectKey() }, // https://jira.zhenguanyu.com/rest/api/2/project/$PROJECT 可以获取 issuetype 列表 issuetype: issuetype != null ? { id: issuetype } : null, assignee: { name: assignee }, reporter: reporter != null ? { name: reporter } : null, labels: [process.env.NODE_ENV === 'production' ? 'jira-import' : 'jira-import__debug'] .concat(labels) .filter(Boolean), priority: priority != null ? { // Low Medium High name: priority || 'Low' // id: '20000' } : null }, data ) ) if (!assignee) { delete config.assignee } if (!reporter) { delete config.reporter } return config } async createIssue(reqBody: Parameters[0], { toast = true } = {}) { const res = await this.request({ method: 'POST', url: '/issue', data: { fields: this._createIssueReqBody(reqBody) } }) if (!toast) { return res } const key = res.data.key if (key) { notification.success({ message: '创建 Jira Issue 成功', description: (
{key}
) }) } else if (res.data.errors && Object.keys(res.data.errors).length) { this._toastErrors(res.data.errors) } else if (res.data.errorMessages && res.data.errorMessages.length) { this._toastErrors(res.data.errorMessages) } return res } async createIssues( { tasksBody, ...reqBody }: Parameters[0] & { tasksBody?: Array[0]> } = {}, { toastSuccess = true } = {} ) { const res = await this.request({ method: 'POST', url: '/issue/bulk', data: { issueUpdates: tasksBody.map((body) => ({ fields: this._createIssueReqBody({ ...reqBody, ...body }) })) } }) const issues = res.data.issues if (toastSuccess && issues && issues.length) { notification.success({ message: '创建 Jira Issue 成功', description: ( x.key).join(',')})` } })} target={'_blank'} > {issues.map((x) => x.key).join(',')} ) }) return } if (res.data.errors && res.data.errors[0] && res.data.errors[0].elementErrors) { const elementErrors = res.data.errors[0].elementErrors this._toastErrors(elementErrors?.errorMessages?.length ? elementErrors.errorMessages : elementErrors.errors) } return res } private _toastErrors(errors, config?) { if (!errors) { return false } if (typeof errors === 'object' && !Array.isArray(errors)) { errors = Object.keys(errors).map((name) => `${name}: ${errors[name]}`) } if (!errors.length) { return false } notification.error({ message: '创建 Jira Issue 失败', description: (
{errors.map((message) => ( {message} ))}
), ...config }) } queryProject(key = JIRA.API.Projects.getCurrentProjectKey()) { return this.request({ method: 'get', url: `/project/${key}` }) } }