import pizza from 'react-pizza'
import { HotKeyChainManager } from 'hotkey-chain'
import lazy from 'lazy-value'
import uniqBy from 'lodash.uniqby'
import React from 'react'
import open from '@rcp/util.open'
import { useJiraApi, useSharedValue, useToken } from '../shared/utils'
import { Alert, Form, Modal, notification, Spin, Switch, Tooltip, Typography } from 'antd'
import uniq from 'lodash.uniq'
import copy from 'copy-text-to-clipboard'
import * as urlUtils from 'url'
import { getIssueKeys, reloadDetailView, reloadIssue } from '../shared/jira-helper'
import UserSuggest from '../component/user-suggest'
import JiraApiBrowser from '../shared/jira-api-browser'
const getDom = lazy(() => {
const div = document.createElement('div')
div.classList.add('jira-extension-hotkey')
document.body.appendChild(div)
return div
})
const initialValue = {
assigneeSubTask: true,
assigneeParentTask: true
}
function AssignModal({ cb, keys, jiraApi }: any) {
const [form] = Form.useForm()
const [data, setData] = React.useState([])
const [isLoading, setLoading] = React.useState(false)
const [setting, setSetting] = useSharedValue('jira-extension-hotkey-render', initialValue)
React.useEffect(() => {
setLoading(true)
jiraApi
.search(`key in (${keys.join(',')})`)
.then((res) => {
if (res.data?.issues) {
setData(res.data?.issues)
const assigneeList = res.data?.issues.map((issue) => {
if (issue.fields?.assignee) {
return issue.fields?.assignee.name
}
})
const prevAssignees = uniq(assigneeList)
if (prevAssignees.length === 1 && prevAssignees[0]) {
form.setFieldsValue({
assignee: prevAssignees[0]
})
} else {
form.setFieldsValue({
assignee: JIRA.Users.LoggedInUser.userName()
})
}
}
})
.finally(() => {
setLoading(false)
})
}, [jiraApi, keys])
React.useEffect(() => {
form.setFieldsValue({
...form.getFieldsValue(),
...setting
})
}, [])
const { parents, subtasks } = React.useMemo(() => {
const parents = []
const subtasks = []
data.forEach((issue) => {
if (issue.fields.parent?.key) {
parents.push(issue.fields.parent)
}
if (issue.fields?.subtasks?.length) {
subtasks.push(...issue.fields?.subtasks)
}
})
return { parents: uniqBy(parents, 'key'), subtasks: uniqBy(subtasks, 'key') }
}, [data, setting.assigneeSubTask])
const renderFields = (fields) => {
return fields.map((field) => (
{field.key}
))
}
return (
{
const values = await form.validateFields()
if (values) {
try {
setLoading(true)
const requestData = data.concat(
values.assigneeParentTask ? parents : [],
values.assigneeSubTask ? subtasks : []
)
await (jiraApi as JiraApiBrowser).setAssignees(
requestData.map((issue) => ({
issueIdOrKey: issue.key,
assignee: { name: values.assignee }
}))
)
await new Promise((resolve) => setTimeout(resolve, 500))
requestData.forEach((issue) => {
reloadIssue(issue.id)
})
reloadDetailView()
notification.success({
message: '分配任务成功'
})
cb(true)
} catch (e) {
console.error(e)
notification.error({
message: '分配任务失败'
})
} finally {
setLoading(false)
}
}
}}
onCancel={() => cb(false)}
>
分配:{renderFields(data)} Issue
{!!parents.length && setting.assigneeParentTask && (
父 Issues:{renderFields(parents)}
)}
{!!subtasks.length && setting.assigneeSubTask && (
子 Issues:{renderFields(subtasks)}
)}
{
总共分配:
{((setting.assigneeSubTask && subtasks.length) || 0) +
((setting.assigneeParentTask && parents.length) || 0) +
data.length}{' '}
个 Issue
}
>
}
type="info"
/>
{!!parents.length && (
)}
{!!subtasks.length && (
)}
)
}
function HotKey() {
const [setting] = useSharedValue('jira-extension-setting')
const token = useToken()
const jiraApi = useJiraApi()
React.useEffect(() => {
if (!setting?.overwriteShortcut || !token) {
return
}
const m = new HotKeyChainManager(window.document as any)
.on('a', (event: KeyboardEvent, next) => {
// @ts-ignore
if (!['TEXTAREA', 'INPUT'].includes(event.target.tagName) && event.target.contentEditable !== true) {
event.preventDefault()
const keys = getIssueKeys()
if (!keys.length) {
return
}
open((cb) => )
}
next()
})
.on('mod+shift+c', (event: any, next) => {
if (!['TEXTAREA', 'INPUT'].includes(event.target.tagName) && event.target.contentEditable !== true) {
event.preventDefault()
const keys = getIssueKeys()
if (!keys.length) {
return
}
const msg = keys
.map((key) =>
urlUtils.format({
...location,
pathname: `/browse/${key}`,
search: null,
query: {},
hash: null
})
)
.join('\n')
if (copy(msg)) {
notification.success({
message: '复制 issue 链接成功'
})
}
}
next()
})
.on('mod+shift+s', async (event: any, next) => {
if (!['TEXTAREA', 'INPUT'].includes(event.target.tagName) && event.target.contentEditable !== true) {
event.preventDefault()
const keys = getIssueKeys()
if (!keys.length) {
return
}
const issuesResponse = await jiraApi.search(`key in (${keys.join(',')})`)
if (issuesResponse?.data?.issues?.length) {
const msg = issuesResponse?.data?.issues
.map(
(issue) =>
`${issuesResponse?.data?.issues.length > 1 ? '- ' : ''}${issue.fields?.summary} ${urlUtils.format({
...location,
pathname: `/browse/${issue.key}`,
search: null,
query: {},
hash: null
})}`
)
.join('\n')
if (copy(msg)) {
notification.success({
message: '复制 issue 分享链接成功'
})
return
}
}
notification.error({
message: '复制 issue 分享链接失败'
})
}
next()
})
.start()
return () => m.stop()
}, [setting?.overwriteShortcut, token, jiraApi])
return null
}
export default function hotkeyRender() {
return pizza(HotKey)(getDom(), {})
}