YouTrack および Hub ヘルプの開発者ポータル

ヘルプデスク

このワークフローは、ヘルプデスクプロジェクトに関連する一般的な使用例を自動化するために使用されます。

名前

@jetbrains/youtrack-workflow-helpdesk

自動添付

いいえ

ルール

  • 課題追跡にコピー (アクション)

  • 重複したチケットを統合する (変更時のルール)

  • チケットを手動でマージする (アクションルール)

  • 報告者に通知し、保留中のチケットを自動的に閉じる (スケジュールルール)

  • 報告者がコメントを追加したときにチケットを再開する (変更時のルール)

  • 最初の返信の作成者にチケットを割り当てる (変更時のルール)

  • コメントからの新しいチケット (アクションルール)

ユースケース

このワークフローは、ヘルプデスクプロジェクトに関連する拡張機能を提供します。

エージェントが、ヘルプデスクと同じ時間制約や SLA の対象ではない別の部門で処理する必要があるチケットに遭遇した場合、課題追跡にコピーアクションを使用して、チケットのコピーを別のプロジェクトの課題として作成できます。これは、たとえば、報告者が開発チームで対処する必要があるバグレポートや機能要求を送信するときに便利です。

ヘルプデスクエージェントは、同じ報告者によって以前に送信されたサポートリクエストと一致するチケットを見つけた場合、チケットの 1 つを重複としてマークできます。これにより、コミュニケーションが 1 つのスレッドに統合され、エージェントが矛盾する回答を提供するのを防ぐことができます。エージェントは、重複リンクを使用するか、チケットのアクションメニューのチケットを手動で結合するオプションを使用して、チケットを重複としてマークできます。

エージェントが報告者から別のサポートリクエストとして処理する必要がある応答を受信した場合、コメントからの新しいチケットアクションを使用できます。これにより、コメントテキストが取得され、新しいチケットの説明フィールドにコピーされ、エージェントに概要を入力するよう求められます。

エージェントがチケット内の報告者に応答すると、チケットを保留状態に移行して SLA タイマーを一時停止できます。この状態は、エージェントが報告者が質問に答えるか、実行されたアクションを確認するのを待っていることを示します。

  • 報告者が指定された時間枠内に返信しない場合、リマインダーが報告者に送信されます。

  • 一定時間が経過してもエージェントが報告者からの応答がない場合、チケットは自動的にクローズされます。チケットがクローズされたことを知らせる追加のメッセージが報告者に送信されます。

報告者が保留として設定されたチケットにコメントを追加すると、そのチケットは自動的に再度開かれます。これは、アクティブな SLA ポリシーに従って解決時間が確実に追跡されるようにできます。

モジュール

このワークフローは、ヘルプデスクプロジェクトでチケットを処理するために使用できるいくつかのルールをサポートしています。

課題追跡にコピー

このルールは、ヘルプデスクプロジェクトのチケットに適用されるサービスレベル契約に従って処理されることが意図されていないリクエストをエージェントが処理できます。エージェントがチケットでこのアクションを選択すると、次のようになります。

  • 新しい課題が作成されるターゲットプロジェクトを選択するように求められます。

  • 対象プロジェクトの選択を確認すると、チケットのコピーが対象プロジェクトの課題として作成されます。

  • ヘルプデスクチケットから新しい課題へのリンクが自動的に追加されます。

このアクションは、現在のヘルプデスクプロジェクトでエージェントライセンスが付与されているユーザーのみが使用できます。標準ユーザーまたは他のヘルプデスクプロジェクトのエージェントには、チケットで使用可能なアクションのリストにこのオプションは表示されません。

const workflow = require('@jetbrains/youtrack-scripting-api/workflow'); const entities = require('@jetbrains/youtrack-scripting-api/entities'); exports.rule = entities.Issue.action({ title: 'Copy to issue tracker', command: 'copy to issue', guard: (ctx) => { return ctx.issue.project.isAgent(ctx.currentUser) && ctx.issue.isReported; }, action: function (ctx) { workflow.check(ctx.userInput.projectType.typeName !== "Helpdesk", "Please select a standard issue-tracking project") const issue = ctx.issue; const newIssue = issue.copy(ctx.userInput); workflow.message('A copy of this ticket was created in the {0} project as <a href="{1}">{2}</a>', ctx.userInput.name, newIssue.url, newIssue.id); issue.links['relates to'].add(newIssue); }, requirements: { Relates: { type: entities.IssueLinkPrototype, outward: 'relates to' } }, userInput: { type: entities.Project, description: 'Target project' } });

重複したチケットを統合する

このルールは、ヘルプデスクプロジェクトで重複したチケットを管理するために使用されます。チケットが別のチケットの重複としてマークされている場合、この変更時ルールは両方のチケットが同じユーザーによって報告されたかどうかをチェックします。

  • チケットが別の人によって報告された場合、エラーメッセージがエージェントに表示され、操作は元に戻されます。

  • 同じ人が両方のチケットを報告した場合、重複としてマークされたチケットにパブリックコメントが投稿されます。コメントには、現在アクティブなチケットへのリンクが含まれています。

const entities = require('@jetbrains/youtrack-scripting-api/entities'); const workflow = require('@jetbrains/youtrack-scripting-api/workflow'); exports.rule = entities.Issue.onChange({ title: 'Merge duplicate tickets', guard: (ctx) => { return ctx.issue.links['duplicates'].added.isNotEmpty(); }, action: (ctx) => { const duplicate = ctx.issue.links['duplicates'].added.first(); workflow.check(duplicate.reporter.login === ctx.issue.reporter.login, "You can only merge tickets where the reporter is the same person") const commnet = ctx.issue.addComment("This ticket was merged into {0}, which was also reported by you.", duplicate.id) commnet.permittedUsers.clear() commnet.permittedGroups.clear() }, requirements: { Duplicate: { type: entities.IssueLinkPrototype, outward: 'is duplicated by', inward: 'duplicates' } } });

チケットを手動でマージする

このアクションルールにより、エージェントは merge with コマンドを使用して重複したチケットをマージできます。エージェントがこのコマンドを指定すると、マージするチケットの ID を入力するよう求められます。

このアクションにより、重複リンクが現在のチケットに適用され、上記の重複したチケットを統合するワークフロールールがトリガーされます。

const entities = require('@jetbrains/youtrack-scripting-api/entities'); exports.rule = entities.Issue.action({ title: 'Merge tickets manually', command: 'merge with', guard: function (ctx) { return ctx.issue.project.isAgent(ctx.currentUser) && ctx.issue.isReported; }, action: function (ctx) { const source = ctx.issue; const target = ctx.userInput; source.links['duplicates'].add(target); }, requirements: { Duplicate: { type: entities.IssueLinkPrototype, outward: 'is duplicated by', inward: 'duplicates' } }, userInput: { type: entities.Issue, description: 'Target ticket for merge' } });

報告者がコメントを追加したら再開

この変更時ルールは、報告者がコメントを追加するたびに、状態フィールドの値を保留からオープンに自動的に変更します。

const entities = require('@jetbrains/youtrack-scripting-api/entities'); exports.rule = entities.Issue.onChange({ title: 'Reopen ticket when reporter adds a comment', guard: (ctx) => { return !ctx.issue.comments.added.isEmpty() && ctx.issue.reporter.login === ctx.issue.comments.added.first().author.login && ctx.issue.fields.State.name === ctx.State.Pending.name; }, action: (ctx) => { ctx.issue.fields.State = ctx.State.Open; }, requirements: { State: { type: entities.State.fieldType, Pending: {}, Open: {} } } });

コメントからの新しいチケット

このアクションルールにより、エージェントはチケット内のコメントのテキストをヘルプデスクプロジェクト内の別のチケットを報告するための基礎として使用できるようになります。エージェントは、新しいチケットの概要を入力するように求められます。

このアクションが適用されると、新しいチケットを参照するコメントが元のチケットに投稿されます。元のコメントへのリンクを含むコメントも新しいチケットに追加されます。

const entities = require('@jetbrains/youtrack-scripting-api/entities'); const workflow = require('@jetbrains/youtrack-scripting-api/workflow'); exports.rule = entities.IssueComment.action({ title: 'New ticket from comment', command: 'toTicket', guard: function (ctx) { return ctx.issueComment.permittedGroups.isEmpty() && ctx.issueComment.permittedUsers.isEmpty() && ctx.issueComment.issue.project.isAgent(ctx.currentUser) }, action: function (ctx) { const description = ctx.issueComment.text; let issue = ctx.issueComment.issue; const author = issue.reporter; const project = issue.project; const commentIssue = new entities.Issue(author, project, ctx.userInput); commentIssue.description = description; const info = issue.addComment('A related ticket ({0}) has been created based on a comment from this ticket.', commentIssue.id) commentIssue.addComment('This ticket was created from a [comment in another ticket]({0}).', ctx.issueComment.url) info.permittedUsers.clear() info.permittedGroups.clear() }, userInput: { type: 'string', description: 'Ticket summary' } });

報告者に通知し、保留中のチケットを自動的に閉じる

このスケジュール規則は、状態フィールドの値が保留であるチケットをチェックします。

  • チケットが 7 日以上保留されている場合、リマインダーが報告者に送信されます。

  • 2 回目のリマインダーは 14 日後に送信されます。

  • チケットが 21 日経っても保留中の場合は、チケットにコメントが投稿され、その状態は Solved に設定されます。

var entities = require('@jetbrains/youtrack-scripting-api/entities'); var workflow = require('@jetbrains/youtrack-scripting-api/workflow'); const firstReminderPolicyDays = 7; const secondReminderPolicyDays = 14; const retentionPolicyDays = 21; const oneDayMillis = 24 * 60 * 60 * 1000; exports.rule = entities.Issue.onSchedule({ title: "Remind reporters and close pending tickets automatically", cron: '0 0 0 * * ?', search: 'State: Pending', action: function (ctx) { const reporter = ctx.issue.reporter; let lastPublicComment = null; ctx.issue.comments.forEach(comment => { if (comment.author.login === reporter.login) { lastPublicComment = null; } else if (comment.permittedUsers.isEmpty() && comment.permittedGroups.isEmpty()) { lastPublicComment = comment; } }); if (lastPublicComment === null) { console.trace('Checking ticket ' + ctx.issue.id + ', last comment is not from the agent'); return; } const pendingIntervalDays = (ctx.ruleStarted - lastPublicComment.created) / oneDayMillis; if (pendingIntervalDays < firstReminderPolicyDays) { console.trace('Checking ticket ' + ctx.issue.id + ', too early to remind, pending = ' + pendingIntervalDays); return; } if (pendingIntervalDays > retentionPolicyDays + 1) { console.trace('Checking ticket ' + ctx.issue.id + ', too late to remind, pending = ' + pendingIntervalDays); return; } const firstReminderOverdue = pendingIntervalDays - firstReminderPolicyDays; if (firstReminderOverdue > 0 && firstReminderOverdue < 1) { reporter.notifyOnCase('reporterReminder', {}, ctx.issue); return; } const secondReminderOverdue = pendingIntervalDays - secondReminderPolicyDays; if (secondReminderOverdue > 0 && secondReminderOverdue < 1) { const params = { 'autoCloseDays': retentionPolicyDays - secondReminderPolicyDays }; reporter.notifyOnCase('reporterReminder', params, ctx.issue); return; } const autoCloseOverdue = pendingIntervalDays - retentionPolicyDays; if (autoCloseOverdue >= 0 && autoCloseOverdue < 1) { ctx.issue.fields.State = ctx.State.Solved; const params = { 'responseTimeoutDays': retentionPolicyDays }; reporter.notifyOnCase('reporterTicketClosed', params, ctx.issue); } }, requirements: { State: { type: entities.State.fieldType, Pending: {}, Solved: { name: 'Solved', isResolved: true } } } });

リマインダーの送信と放棄されたチケットのクローズの時間枠をカスタマイズする場合は、ワークフローコードで次の値を直接変更できます。

説明

firstReminderPolicyDays

最初のリマインダーを送信するまでに待機する日数。

secondReminderPolicyDays

2 回目のリマインダーを送信するまで待機する日数。

retentionPolicyDays

チケットを自動的に閉じるまで待機する日数。

最初の返信の作成者にチケットを割り当てる

未割り当てのチケットがエージェントからコメントを受け取ると、この変更時ルールにより、コメントの作成者であるエージェントにチケットが自動的に割り当てられます。

const entities = require('@jetbrains/youtrack-scripting-api/entities'); exports.rule = entities.Issue.onChange({ title: 'Assign ticket to author of first reply', guard: (ctx) => { const issue = ctx.issue; if (!issue.fields.Assignee && issue.comments.added.isNotEmpty() && issue.project.isAgent(ctx.currentUser)) { let hasAgentComment = false; let result = true; issue.comments.forEach(function (comment) { if (result && issue.project.isAgent(comment.author)) { if (hasAgentComment) { result = false; } else { hasAgentComment = true; } } }) return result; } return false; }, action: (ctx) => { const issue = ctx.issue if (issue.project.findFieldByName(ctx.Assignee.name).findValueByLogin(ctx.currentUser.login)) { issue.fields.Assignee = ctx.currentUser; } }, requirements: { Assignee: { type: entities.User.fieldType } } });
2025 年 11 月 21 日