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" />
{ let change if ( (change = changes.find((change) => { // @ts-ignore return change.name?.find((x) => Object.keys(initialValue).includes(x)) })) ) { setSetting((v) => ({ ...v, [change.name[0]]: change.value })) } }} > {!!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(), {}) }