From 9ea5e9e87a0245d45c2e394e2723fe0d65b74ae0 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 5 Dec 2017 12:54:32 +0200 Subject: [PATCH 01/17] Add jira board column --- css/normalize.css | 447 ++++++++++++++++++++++++++++++++++++++++++ css/options.css | 35 ++++ index.js | 14 +- lib/Config.js | 11 +- lib/PageController.js | 6 + view/options.html | 12 +- 6 files changed, 514 insertions(+), 11 deletions(-) create mode 100644 css/normalize.css create mode 100644 css/options.css diff --git a/css/normalize.css b/css/normalize.css new file mode 100644 index 0000000..fa4e73d --- /dev/null +++ b/css/normalize.css @@ -0,0 +1,447 @@ +/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * 1. Remove the bottom border in Chrome 57- and Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} diff --git a/css/options.css b/css/options.css new file mode 100644 index 0000000..4ee4151 --- /dev/null +++ b/css/options.css @@ -0,0 +1,35 @@ +* { + box-sizing: border-box; +} + +.form-title { + text-align: center; +} + +.config-form { + margin: 2rem auto; + width: 20rem; +} + +.form-text { + font-size: 1rem; + margin-top: 0.5rem; + height: 2rem; + width: 100%; +} + +.form-entry { + display: block; + margin-top: 2rem; +} + +.form-textarea { + font-size: 1rem; + width: 100%; + height: 10rem; +} + +.btn { + padding: 0.5rem 1rem; + width: 100%; +} diff --git a/index.js b/index.js index 861a2e0..c270ad7 100644 --- a/index.js +++ b/index.js @@ -36,7 +36,7 @@ chrome.browserAction.onClicked.addListener(() => { selector: '#merge_title_field', mapper: e => e.value, }, - updateJiraTicket: { + hasToUpdateJiraTicket: { strategy: 'js-eval', code: 'confirm(\'Do you want to update jira ticket ?\')', } @@ -46,21 +46,25 @@ chrome.browserAction.onClicked.addListener(() => { return config.users[reviewer] || reviewer.toLowerCase(); }); + const {jiraTicket, hasToUpdateJiraTicket} = data; const jiraApi = new JiraApiClient(pluginConfig.get('jiraBase')); + const boardColumnName = pluginConfig.get('boardColumn'); const commitMessage = templateDriver.renderToString(pluginConfig.get('template'), data); const mergeTitle = templateDriver.renderToString('{{ title | clear }}', { emojis: config.emojis, title: data.mergeTitle, }); - const updateJiraTicket = data.jiraTicket && data.updateJiraTicket + const updateJiraTicket = jiraTicket && hasToUpdateJiraTicket ? jiraApi - .getTransitions(data.jiraTicket) + .getTransitions(jiraTicket) .then(response => { - const toDevCompleteTransition = response.data.transitions.find(t => /dev\s+complete/i.test(t.name)); + const toDevCompleteTransition = response.data.transitions.find(t => new RegExp(boardColumnName, 'i').test(t.name)); + const {id, name} = toDevCompleteTransition; return toDevCompleteTransition - ? jiraApi.postTransition(data.jiraTicket, {transition: {id: toDevCompleteTransition.id}}) + ? jiraApi.postTransition(jiraTicket, {transition: {id}}) + .then(() => controller.alert(`Ticket ${jiraTicket} successfully moved to ${name}`)) : Promise.resolve(); }) : Promise.resolve(); diff --git a/lib/Config.js b/lib/Config.js index c85fe5a..82acbd8 100644 --- a/lib/Config.js +++ b/lib/Config.js @@ -1,3 +1,9 @@ +export const defaultOptions = { + jiraBase: 'https://yourdomain.atlassian.net', + template: 'Jira: {{ jiraTicket }}\nReviewers: {{ reviewers | join }}\nPR: GH-{{ prNumber }}', + boardColumn: 'dev complete', +}; + export class Config { constructor() { this._options = {}; @@ -5,10 +11,7 @@ export class Config { load() { return new Promise(resolve => { - chrome.storage.sync.get({ - jiraBase: 'https://yourdomain.atlassian.com', - template: 'Jira: {{ jiraTicket }}\nReviewers: {{ reviewers | join }}\nPR: GH-{{ prNumber }}', - }, items => { + chrome.storage.sync.get(defaultOptions, items => { this._options = items; resolve(); diff --git a/lib/PageController.js b/lib/PageController.js index 48dcfa3..f47e73b 100644 --- a/lib/PageController.js +++ b/lib/PageController.js @@ -19,6 +19,12 @@ export class PageController { return this.executeCode(code); } + alert(message) { + const code = `alert("${message}")`; + + return this.executeCode(code); + } + /** * @param {String} selector * @returns {Promise} diff --git a/view/options.html b/view/options.html index 7cfc93b..b976368 100644 --- a/view/options.html +++ b/view/options.html @@ -8,10 +8,18 @@

Git Merger

+ +
+ +
+

Enter commit template:

From dc5723238654cb1e3490a79da0517cb65fe14e09 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 5 Dec 2017 12:58:24 +0200 Subject: [PATCH 02/17] update placeholders --- lib/Config.js | 2 +- options.js | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/Config.js b/lib/Config.js index 82acbd8..834567a 100644 --- a/lib/Config.js +++ b/lib/Config.js @@ -1,7 +1,7 @@ export const defaultOptions = { jiraBase: 'https://yourdomain.atlassian.net', template: 'Jira: {{ jiraTicket }}\nReviewers: {{ reviewers | join }}\nPR: GH-{{ prNumber }}', - boardColumn: 'dev complete', + boardColumn: 'complete', }; export class Config { diff --git a/options.js b/options.js index b0c97e1..d8bb45d 100644 --- a/options.js +++ b/options.js @@ -1,12 +1,15 @@ -import './normalize.css'; -import './options.css'; +import './css/normalize.css'; +import './css/options.css'; +import {defaultOptions} from './lib/Config'; function saveOptions() { - const jiraBase = document.getElementById('jiraurl').value; + const jiraBase = document.getElementById('jiraBase').value; + const boardColumn = document.getElementById('boardColumn').value; const template = document.getElementById('template').value; chrome.storage.sync.set({ jiraBase, + boardColumn, template, }, () => { // Update status to let user know options were saved. @@ -21,11 +24,9 @@ function saveOptions() { } function loadOptions() { - chrome.storage.sync.get({ - jiraBase: 'https://yourdomain.atlassian.com', - template: 'Jira: {{ jiraTicket }}\nReviewers: {{ reviewers | join }}\nPR: GH-{{ prNumber }}', - }, items => { - document.getElementById('jiraurl').value = items.jiraBase; + chrome.storage.sync.get(defaultOptions, items => { + document.getElementById('jiraBase').value = items.jiraBase; + document.getElementById('boardColumn').value = items.boardColumn; document.getElementById('template').value = items.template; }); } From 4e2756c31ed0849643173070e2c42daec5ff4c98 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 5 Dec 2017 13:00:47 +0200 Subject: [PATCH 03/17] remove unused files --- normalize.css | 447 -------------------------------------------------- options.css | 35 ---- 2 files changed, 482 deletions(-) delete mode 100644 normalize.css delete mode 100644 options.css diff --git a/normalize.css b/normalize.css deleted file mode 100644 index fa4e73d..0000000 --- a/normalize.css +++ /dev/null @@ -1,447 +0,0 @@ -/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */ - -/* Document - ========================================================================== */ - -/** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in - * IE on Windows Phone and in iOS. - */ - -html { - line-height: 1.15; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* Sections - ========================================================================== */ - -/** - * Remove the margin in all browsers (opinionated). - */ - -body { - margin: 0; -} - -/** - * Add the correct display in IE 9-. - */ - -article, -aside, -footer, -header, -nav, -section { - display: block; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/* Grouping content - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - * 1. Add the correct display in IE. - */ - -figcaption, -figure, -main { /* 1 */ - display: block; -} - -/** - * Add the correct margin in IE 8. - */ - -figure { - margin: 1em 40px; -} - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -pre { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* Text-level semantics - ========================================================================== */ - -/** - * 1. Remove the gray background on active links in IE 10. - * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. - */ - -a { - background-color: transparent; /* 1 */ - -webkit-text-decoration-skip: objects; /* 2 */ -} - -/** - * 1. Remove the bottom border in Chrome 57- and Firefox 39-. - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Prevent the duplicate application of `bolder` by the next rule in Safari 6. - */ - -b, -strong { - font-weight: inherit; -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -samp { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** - * Add the correct font style in Android 4.3-. - */ - -dfn { - font-style: italic; -} - -/** - * Add the correct background and color in IE 9-. - */ - -mark { - background-color: #ff0; - color: #000; -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - */ - -audio, -video { - display: inline-block; -} - -/** - * Add the correct display in iOS 4-7. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Remove the border on images inside links in IE 10-. - */ - -img { - border-style: none; -} - -/** - * Hide the overflow in IE. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Forms - ========================================================================== */ - -/** - * 1. Change the font styles in all browsers (opinionated). - * 2. Remove the margin in Firefox and Safari. - */ - -button, -input, -optgroup, -select, -textarea { - font-family: sans-serif; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ - -button, -input { /* 1 */ - overflow: visible; -} - -/** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` - * controls in Android 4. - * 2. Correct the inability to style clickable types in iOS and Safari. - */ - -button, -html [type="button"], /* 1 */ -[type="reset"], -[type="submit"] { - -webkit-appearance: button; /* 2 */ -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Correct the padding in Firefox. - */ - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * 1. Add the correct display in IE 9-. - * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Remove the default vertical scrollbar in IE. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10-. - * 2. Remove the padding in IE 10-. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** - * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. - */ - -[type="search"]::-webkit-search-cancel-button, -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* Interactive - ========================================================================== */ - -/* - * Add the correct display in IE 9-. - * 1. Add the correct display in Edge, IE, and Firefox. - */ - -details, /* 1 */ -menu { - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { - display: list-item; -} - -/* Scripting - ========================================================================== */ - -/** - * Add the correct display in IE 9-. - */ - -canvas { - display: inline-block; -} - -/** - * Add the correct display in IE. - */ - -template { - display: none; -} - -/* Hidden - ========================================================================== */ - -/** - * Add the correct display in IE 10-. - */ - -[hidden] { - display: none; -} diff --git a/options.css b/options.css deleted file mode 100644 index 4ee4151..0000000 --- a/options.css +++ /dev/null @@ -1,35 +0,0 @@ -* { - box-sizing: border-box; -} - -.form-title { - text-align: center; -} - -.config-form { - margin: 2rem auto; - width: 20rem; -} - -.form-text { - font-size: 1rem; - margin-top: 0.5rem; - height: 2rem; - width: 100%; -} - -.form-entry { - display: block; - margin-top: 2rem; -} - -.form-textarea { - font-size: 1rem; - width: 100%; - height: 10rem; -} - -.btn { - padding: 0.5rem 1rem; - width: 100%; -} From 863cc1f5b2d428bb905cd09a1546206bdd83bb69 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 5 Dec 2017 15:58:48 +0200 Subject: [PATCH 04/17] Implement github aliases --- index.js | 4 +++- lib/Config.js | 3 +++ npm-debug.log | 27 +++++++++++++++++++++++++++ options.js | 3 +++ view/options.html | 12 +++++++++--- 5 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 npm-debug.log diff --git a/index.js b/index.js index 821c4ae..f29e7eb 100644 --- a/index.js +++ b/index.js @@ -41,8 +41,10 @@ chrome.browserAction.onClicked.addListener(() => { code: 'confirm(\'Do you want to update jira ticket ?\')', } })).then(data => { + const userAliases = pluginConfig.get('userAliases'); + data.reviewers = data.reviewers.map(reviewer => { - return config.users[reviewer] || reviewer.toLowerCase(); + return userAliases[reviewer] || reviewer.toLowerCase(); }); const {jiraTicket, hasToUpdateJiraTicket} = data; diff --git a/lib/Config.js b/lib/Config.js index 834567a..27ccdfb 100644 --- a/lib/Config.js +++ b/lib/Config.js @@ -2,6 +2,9 @@ export const defaultOptions = { jiraBase: 'https://yourdomain.atlassian.net', template: 'Jira: {{ jiraTicket }}\nReviewers: {{ reviewers | join }}\nPR: GH-{{ prNumber }}', boardColumn: 'complete', + userAliases: { + userName: 'first.lastName', + }, }; export class Config { diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 0000000..69bdc7e --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,27 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/node', +1 verbose cli '/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/npm', +1 verbose cli 'run', +1 verbose cli 'build:wathc' ] +2 info using npm@3.10.10 +3 info using node@v6.11.0 +4 verbose stack Error: missing script: build:wathc +4 verbose stack at run (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/lib/run-script.js:151:19) +4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/lib/run-script.js:61:5 +4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:356:5 +4 verbose stack at checkBinReferences_ (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:320:45) +4 verbose stack at final (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:354:3) +4 verbose stack at then (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:124:5) +4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:311:12 +4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16 +4 verbose stack at tryToString (fs.js:456:3) +4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:443:12) +5 verbose cwd /Users/ntrandafil/jsProjects/GitPR +6 error Darwin 16.7.0 +7 error argv "/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/node" "/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/npm" "run" "build:wathc" +8 error node v6.11.0 +9 error npm v3.10.10 +10 error missing script: build:wathc +11 error If you need help, you may report this error at: +11 error +12 verbose exit [ 1, true ] diff --git a/options.js b/options.js index d8bb45d..9ad5078 100644 --- a/options.js +++ b/options.js @@ -6,11 +6,13 @@ function saveOptions() { const jiraBase = document.getElementById('jiraBase').value; const boardColumn = document.getElementById('boardColumn').value; const template = document.getElementById('template').value; + const userAliases = JSON.parse(document.getElementById('userAliases').value); chrome.storage.sync.set({ jiraBase, boardColumn, template, + userAliases, }, () => { // Update status to let user know options were saved. const status = document.getElementById('status'); @@ -28,6 +30,7 @@ function loadOptions() { document.getElementById('jiraBase').value = items.jiraBase; document.getElementById('boardColumn').value = items.boardColumn; document.getElementById('template').value = items.template; + document.getElementById('userAliases').value = JSON.stringify(items.userAliases, null, ' '); }); } diff --git a/view/options.html b/view/options.html index b976368..6a29b9f 100644 --- a/view/options.html +++ b/view/options.html @@ -24,9 +24,15 @@

Git Merger

Enter commit template:

+
+ +
+

Enter github aliases json to map firstName.lastName instead of github nickNames:

+ +
From b7091be6b309361318db02b1f341bc5f8b26bd31 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 5 Dec 2017 16:25:56 +0200 Subject: [PATCH 05/17] Update placeholders remove unused files --- index.js | 2 -- lib/Config.js | 2 +- npm-debug.log | 27 --------------------------- view/options.html | 2 +- 4 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 npm-debug.log diff --git a/index.js b/index.js index f29e7eb..5f0addc 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,6 @@ import {MetadataReader} from './lib/MetadataReader'; import {PageController} from './lib/PageController'; import {SimpleTemplateDriver} from './lib/SimpleTemplateDriver'; import {JiraApiClient} from './lib/JiraApiClient'; -import config from './config'; import {Config} from './lib/Config'; chrome.browserAction.onClicked.addListener(() => { @@ -52,7 +51,6 @@ chrome.browserAction.onClicked.addListener(() => { const boardColumnName = pluginConfig.get('boardColumn'); const commitMessage = templateDriver.renderToString(pluginConfig.get('template'), data); const mergeTitle = templateDriver.renderToString('{{ title | clear }}', { - emojis: config.emojis, title: data.mergeTitle, }); diff --git a/lib/Config.js b/lib/Config.js index 318d57f..55e5bf4 100644 --- a/lib/Config.js +++ b/lib/Config.js @@ -1,7 +1,7 @@ export const defaultOptions = { jiraBase: 'https://yourdomain.atlassian.net', template: 'Jira: {{ jiraTicket }}\nReviewers: {{ reviewers | join }}\nPR: GH-{{ prNumber }}', - boardColumn: 'complete', + boardColumn: 'dev complete', userAliases: { userName: 'first.lastName', }, diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index 69bdc7e..0000000 --- a/npm-debug.log +++ /dev/null @@ -1,27 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/node', -1 verbose cli '/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/npm', -1 verbose cli 'run', -1 verbose cli 'build:wathc' ] -2 info using npm@3.10.10 -3 info using node@v6.11.0 -4 verbose stack Error: missing script: build:wathc -4 verbose stack at run (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/lib/run-script.js:151:19) -4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/lib/run-script.js:61:5 -4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:356:5 -4 verbose stack at checkBinReferences_ (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:320:45) -4 verbose stack at final (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:354:3) -4 verbose stack at then (/Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:124:5) -4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/read-package-json/read-json.js:311:12 -4 verbose stack at /Users/ntrandafil/.nvm/versions/node/v6.11.0/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:78:16 -4 verbose stack at tryToString (fs.js:456:3) -4 verbose stack at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:443:12) -5 verbose cwd /Users/ntrandafil/jsProjects/GitPR -6 error Darwin 16.7.0 -7 error argv "/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/node" "/Users/ntrandafil/.nvm/versions/node/v6.11.0/bin/npm" "run" "build:wathc" -8 error node v6.11.0 -9 error npm v3.10.10 -10 error missing script: build:wathc -11 error If you need help, you may report this error at: -11 error -12 verbose exit [ 1, true ] diff --git a/view/options.html b/view/options.html index 6a29b9f..ad41c48 100644 --- a/view/options.html +++ b/view/options.html @@ -16,7 +16,7 @@

Git Merger

From 03073f2e0882472aedb2fb6c3ce55a77cf64e50f Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 7 Dec 2017 18:58:19 +0200 Subject: [PATCH 06/17] Add icons --- assets/icon128.png | Bin 0 -> 15915 bytes assets/icon16.png | Bin 0 -> 1051 bytes assets/icon48.png | Bin 0 -> 3607 bytes manifest.json | 9 +++++++-- webpack.config.js | 5 ++++- 5 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 assets/icon128.png create mode 100644 assets/icon16.png create mode 100644 assets/icon48.png diff --git a/assets/icon128.png b/assets/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..525fe66b8266f0738ce7c7e0b5a340aaa4ae7f67 GIT binary patch literal 15915 zcma*ObyOU|w?8<*;5N9!;1FDbyADopcXx-Ng9LX1B*ER?-Ge*926qS+f&>Wg%lEyv zZ+HLN?Q^QD`qrmDw{D%&x2mi9#;B{xW1^9w0RR9@1&EBsza09Xgo5<%J|t#7`7Z<7 zN~%Z#01Zj#f6Wp9J%cSF8Y%#QKf^y<1OV{#AN&ab;LQmDoS6XtLSFy?BDd_$4FUgGZslrW&F<&y_74pJi1-QpD>_?y znS=eDom@PH{6uN~3nBEc{2ws~4fwwxUXG$PdMfH*X;%+x@OyS%c1{{GG%y$};$dYY zq#+~sKh6I=iPG44dASL3aQOQAvitI|yL#Aia0v0i$})V)6&D<&CA}^1^gdga|>5*FHstr|0w$3>%aTyWpDF;YjW}YAG7`$$nl>V z4lZ_1j{oKU*Hq*`QXw@Dd+UFi|HCiFCGua$|Cj84^oVf$NBRGwGyiSre@XwDDuyP) z@xQ|+hNe8osQ+&uMHFNtwfx{Na*)l8N75gXa{XO1;^-zD={p`GxmJlSIYav+fheK% z&vOrwBvdmf-XItb1GgU#)epFO%?A?G zLE*4M;kI5RQ8^(11af$U?&ok^vt$6001(OV0hzx4AKVQEKmdC|NlvxFODjq>9TdO=(6|J^oG#slIQjV5pGy!z>T-g zon7vD@V6^QGZJck-%c>lqX>fKexb2z7j{w?+3nvG4!l0Q{+MG+ivlngE{&QEdRK}! zN;ds0xw1uW^+#ynuT8hH-IdkP#KPXLuDB~>$P1KM2E`TW_djc%Qv4$hYS}^CYgl{K zpK7rjtE*bsgXO^yE;(@~ML(N!&bZ6rpV0Tfe5L5@$fqfP1caMIl0^UXn_dj`u{S9! z+O8d5^$y;|$%T6zNNADD(3Is;S?2fihtr*L@OGQu`FPV@e)PwPH5)>AyeJd@Q(M!0 z7~(v&=IMNOPgIj{l@WAo+gHEv3$Lc9XVb#c65$Tif~~4Ogp8U`1!l`lt!+zG4LBHh zzKFZ(8M_%(Ydy~vaddWW`0~f9s;a6b@j$ujzSGpe-oC<{=GAf=fI7#|EiXm4!RdU< zm?j^>9UfLg1%8RtVGat?vkl;QbekdiN&9rwenb!01vaWgKT0y?YL`6TK*gm&h?v?*M#6U7)TclJ zG2DT6N9We8kdHY*cRg24A6*TtE}SWJJ{Y@pVJ#VITb5}r^TBF21DyUuo45WQ6>mCx z*iIPEudP+J%><;DMLIvpAx3Oq3!?IxBM+k#a$bbHz8=1%B|)DN_>(AU1`l_)1Y5Iot_ARRG>&NadR$cgCt-lf^ z<(L__$8m8*J#s^h-$Ku?(@a))>`M6!!dO?~Bjmx6*AGAa`?D^OhF*%VYJV4m-ZONa zuJkoih5cP~HFZ$&PG}7YK^${!Zg1Cfw70L{o0sMDy<`;*+9Fp{R<18SBK&Dr*Cy=R zx7i6Z+z`E8oo7CC-v&X)KG!Ivg8!Tu)eQyx2GrfF+!g$LpNqzjpYOX&x6M|9&v<;+ zWtD15dbhAB%NsN9u>{1o48D;%ZTxBAGdHTB|1Qt^UT}ax^^4h$bmSVdbFZ$8AyHHm=#|Q-T>Gp?X%NP%j^RhI{dJfL%92ttvvgDF%MhamAPNtoZblEBAw1W3T)8+_ ziViop#L51ZMe!K^E_b3^?R~%Z+E$A%(aGFQ26I*ud8!Y3&ADntB+9l-xbxQ0*LJ2j zqwUdU%CBmg{+`4U&J2~ajYCXJilzc_EkS4`^$+258)rykR8d@zG>%BRXTg| z{k+y&IKoblqesZQ`>Q67*XQGEB=G0Y>1$sWxCe7+oe#=s$TGwixSJYTnVBC^Vly^( z9QN?#`xEVkQD2i2by!0dpIYu`uR_|aZLymKp88y8DXRme`l4UHe9?0pr6txkvP)w~ zy!!hSuA;0&_IjhdXyE-+fc z!J+L}R~9a`_IA&BctozEvt+_(+y1t_r{Y%P;3G5WoU@q`-DFV7aeYx$g~Z|$fn?kH=$52h2vokT7&c z`93{oJ~VwIgY5n*@kl3NuXTHss?U2a5}#qcT>p5r`JcNytNzO8e@mQ+i#o2bgvYC3 z#6XAQR%z%3t|5NrpF;t0+cjsBgql&isPWUAfSR06Le8G{{F|Mkgtv3?gH+ zY}ksmQE6nP3htkw5Bq{)9?caNU~1^8c3au|0nUMr!m+BZIm_Kg3E#su@r<)(}~<0e6B|Y|J0E9Am*cYeh6+{jg*Fu;y+0!k^`_ zZqeR5U)kV`%e5zztYu96k>=0Q5fYiPky8b8#WHmaz`R|T?&DS!@Q7$ux_ex#a>I0n zhYM8je5@ntm{vCHRe0vDloxV=2k({)S4=Fk_L*6;Cd1}v;8X%Hp;W^f&oCD}|; zWWIGwj6yw-N*ysAA)}-+*@z*4W~cvHn(4er`>;Oi`vcY-H`B66m}}j1Jl(R;7?Y94 zPo6(41h&$$zm_$L^dx?$M47@mW9q)^zW!oJOl&uRXjJ}PUMZT&_~&l1> z;?KoFhj>@bsGdanhK?+RA=;qklpu*uH(t#|rx;XXp97X2^51CSN0gQ_>c`U06I0?g zP#cQDqJHc$ywz5nqQC!G`kWHz8aUY4%(ZRtM-to)^s1pqTu4lOjGFwO*g{Q$ie>6{ z6{!r&EW?D4F~didfRE^3T3xqqDGytPq|px;EBq=)MWGRV|3fY@%e;tTRA0$5eDkKL z4t5t{;5-4FZQ{wuc5SkmZETR4FJ?FpYH4eMr>jP`xR}ufOh#D-nCp%r0K=0_AnMZI zBG5WeObUuQYK(&;@>o(*TvM!Q*ZH@)z>!Fz*;YMHZDT{rX*RZO>CvH=N^Zgk$98^S zNUk-_(@;NAS(s3Oc&4R)=}=g-KKX34l7#3&X7Pa*?B<3P)>pQnxP=A;n^hr%9b69v z3O|eL!eRq1q5i+Ci%QZ@z}aXXot*v=oTrLceylk*ct-2g$ym^pAFEDWQD>}_r^(T> zIng-U5mwPzv38$`gMZ)6t|p+Q+7opz&h(v7Io;cPa)IT|*@ySV_7h{#DTbEb6>GK? zy@&E`$H-qRhm@hv`rZ4Zae3&XDQ`}0TugX${` z_H+%&g8+`fr1Z4Rn3LXT@fEG-nSHIz8wDBZX)e+`OB2#j)wQi#fCi2j+d`CD%1n%h2#m@QhMxM@(rJy6+@YXJ&`KuE`mdu0@>YLZD%T`#( zwPse(Zii0Nysn|P<1Ytc$j{=OiKCQg-2)z+!Rhgt+j%j@Ze3|YqOqOF_sBJ6#Q7Dp8|KK1FpT{r?%jKBuLDe|vS=PCk zb-K2e*1&utA&ra3gr5Tui~3iAcSx#)H%7jDaxFVLEvZM{8(N#5QR%GJ+fJn?s~s#LJW6qC}8RU1e5T{1bgB+I z^j$oa>PF}v9ED2$P|{Q*G?cV`PN*3XdbO4Eayc7~RIN)Au7n?3)Km9ATOpl7E932j z@uWPPPJQ$ae8ilv3 zj+52J+n~hbC{igDP4wraHSDUf52287lu+4GiD&(NZ1gaFwc7ahlJ;XM*}KWJ>Bsr1 zxlFNWaDHOtSI%!ErS;}T6Ae2bz)(*us(l<03gt**fpQ?`M#rsDnBd>{>T9je$YK8F zafYnShzc3mVHc@Wt06U`JWEL~Pvm5@9MOZ})+d66MJU)|NEH zwF$(rcgAw3;Uoq38LptXDG?OGVj-TWS=P7<8Gt@$s09RPK$N z@mPBYhcMzZr|nQhDoST_BT;H*L|{0ZqF)~Z{5WWqVa_Yngsrxg4h=bijg4pM{>sRj zL^@L6!yqvsTX0nI1BHSgod&f+Bl8aT>AIf<-cxN5e3pRd2HiSAT_)pBWoS>aG)qPZ zx*>9Een$yr#nPZ&2m)6ELncEyGS=LxYA}E2E93f=_dBdYngIEWdqMa@AwJPX&F=+H zIoR-~p|^3;Xcc~M&oL-ZiGc13NzYH^i)wkcAMxUhx|hR?Ki_(-{0?Qp@5MSEU<@Z$ zh{73?1EK38VUh=4=l`Ig27+TO*A8Q`6bX3Gx0SNHVG9eE&JdiTYWg(iu{mmtnnuj& zmh)<5qM>o-@eFw1cfST}oMbvdlxI%z?Zdj*;qyYl!qm@YP^xUK3q4~)c(3Ad6mb93tQH;h>#NI0m3!C&B5ljyfbuo2Yrj)5S(VPhQ$3AO|r7viu$C5MPsA-tc9IdL7p za~Ni*pvP;E?f;-{U81d{rRV8Pv4uU`@AmmUli_d=-I@Ins(pLvy8+D?$GnhR1*X-4 zpDIPan{{YZFQ+wGGGO8yLMsfpePcJfb9A>YvC#eO@9)q0YO&?U!fMg3x%=^TSMWnAco{vBYS?1ijuLXGC>&mun-=w6PH17ur}!_{LLVTQC}890Ni6*XxblxS z&6vb-yXA&|FfJ(mbY_H5i+@HEElQY=`vE_4Dche)S1^{CdtZylr=YIpXEbUNam_@1 z+MY&@D}f`Hp8p9%To{CM_AYOCo2y73HgM(uYYk$IAaZ^7xoEiyF?LzmcohftMf*%7 zp3w3lP7CZcxzb6@X$zqcsrNuvN22p1RWdg}Mg>Ji#GEP-(IDQSe6%n}@Bcu9g0o8w zj2ISvq(yg{SgL4GMsztuua}BgIUlq1N(ky7fv-}$wrVNxoqsQtD4-Vdj+zMh;U|>p z{>)nyM>G@A{2?OWR_TE%*aXtBE9U=(Bb-~hXujDq^XWq36ag8Z>bo70$>?%|;W-Dc45ZM&TbGGz2G=drsf+iBwE`@Du2AK|0+J6?ElNwo)DrK_fbB><>3f zKvA1LKkzFT3VZG#C55M=M0dNCkNUYzCqkHnBhen3P}DjZ{E+}Y*+BD?{O6q~XmS{= zJSG~(#uTDZQWrt^twYn zAF<7qm`o7}BL&I(AY}7B%^~J9D3kwNGOEZs%WR}CK+MbID9kDss8{2vmO?n9VkD%b zXnk)u*Xt{N&)M37iYqT*ZAo7w!x4<{(31DRC$*6*mOZtkGUWP#58Pc5xnd}?eARWs zL|;}NXaWtL_li;Z9Pk}b6_(-LN6n&!%{=Mcf})A3wNqt7i(O_aR248keLjpm>*N&g z=LsGwi$A2q$>joPi1NbZ(g|TRK><#87rwAbDpT7s4wJnt;4i6JQZ)Zb(Qhg;Z>P@q zSd6_tY2gKK2F{9QN{4H_0u5|hjUPj?*GI3~=edbz((_D{#Ru1M8qg-J_Pb_tc_uem zs8yh7$#e}{;nuxWa32bsyT7l*EO*wWJAoE!ZL@BY~j z9G6<(OjYv}w}mnkq41QRf{)TKTT4s$XIJn@2cYskZUc=W8rmo^|dyF++%Ordj zc39(|*P@?%gl$hBb@*E2L(}_n7DabodIVX(&^~&2<09M0rIFP9w^_z+E`9sjL^gJGqWR#G`Y9+=;7w&(_4tF|#shETfa=mxEZZXjsS@_=nI`U^ zYN&VJ_kXKdV&I0!eomCGCL}lv2ty=oD#L~^j0W$VF{u-@`<|8k{xASCp=Dnfu+*s|)Rr zQE{k5^meJ2ZD>Bhe-Th~fAaph0y~<{5)CWe@1g%-*7Gx^S@x31`<-HDZi@9!6Tf*p z-A@o_ZRMkC^LK6Qbh9!M1osLS2Gl#i!Nm%hGrDzY3nKRlHdVjT{Ub|*9})hwfcb~7o~(!xbwJ2_Ty?=5)Hypr{DCQT_A*+Ml`{*!A%@bC}!$Wh7c5~ zPjtxdUXP;npoB&dtiCEW#=SgtdEdDykU9FC1@LZ zNQCcCnrS;UX4&si%kZwXs(WL?_u^&%tbp}zE^;S8`1$IVMqo*_plyU9jS=O(hkffg zFq+agQbGglh~d7zrw}*+to#ak#s-`K#)ET6sphb?PlaVb;ahUURBdi=DXW4vk3wa7 zGT>idge4VUB6ax;Fgq~NiLwX!b#f1-fFEgZoTq6gtDokMovglt97ptStq4Ng@{tl@ zkt=Re2OC$i8`QPVU}np^rmAYc8M?_S2;)lteyc>RTFO>yP^Rep>b}q0%jEfE%k1-K zhr{pV5G4r2X9k0e)FTU{$qlkHOM$t69a(h0`@&u+m?@KO@%yNTl4CAHZ3K;6P!w`y zEcpkNBXWc|FcMm_{QTWASl5s)q1ZqM`229uB2W2oSX&`DxObMNe6xMj$7%cWfr?E( ziLTL7Y)>1T(xyze=lm|`bGg_21b%tC@0OM3jFAK45ZYKn(l3e03}?f0b#FFOE~$Fi z{fCLnGzyNr8g%uN>n%aFuDk}eiWi&s#*U*l-Iy1k_mAAsRZ|(cqlx%V}k6f?6o@Eh$jh-{RR(VQ)sB*Sf9%yZT%RWi;Nua{e zJ42#eyHzrRL~bTMaWj8jR7#cNj^;oRiClX3`*chQ=8hbk+s7z1+>V8M=J<%4i?Gh>xO3FRL6H zjHAGmYRYJ&mj4EKi$Ay4<5(7F++pWk{_YT+GUhK{`8^#6=2EBylOL%_cW38>=(mER zQW(qdd#qGxFs;Tug{prY-lM}2GZ+dWMb_gqe~z`K*k!hl_Ct{kZ03ri1fc zX!{jNWmg#1W4PS4MWl-gm*7XhHg$<>2^q#r0daso(WYz%Po)3%F0~p8V2gp1OEz&s8J>mOKE@!v6(*kNwB=LU%97v z9cF@rmpvz~tR`C;EzbfaR!$={YJDxO=xq;o-W(a6BsSrDp+!@aR2YJC2+#Y;AU0KW zsqU%!5zNob%uvVVcZ|L$DdVcJIyyC+cM&v((xJ3LL}4a1<(CqDlY>dIKXto8Jv&Vf zuea>ycZ;ZR&kMa^ogd@AS0c8GvAoCu-~fe4`2RkCYlqhvT$Au!KeT8;z514*tU>%; z&((&bbxc6F{*A=5%QRLOhHG}O2DVDAuI}*Ma?YRRINF7d>Up8_hPJ+%V%1{iE*HkLG z@E576ProGlw?nOxH^bd}s~`?CU%QVr2B<|C2t2Js2dw>bEhrR}b8EnottqGOou_&$ z_gaDQrca*$Qtz-~1#A2l!>__!FeAirgeT8-L40^20n&2r?}MF*Emv@j7>cb!eb}A` z$q*bc6TrYt^%qh_m`WC3L+S(jBqcY#gkyXAWNcilGWuHdJ_`z3jnN}MPZ)72Lm=DW zht#M`?I4FHt#8q=vTm+yGUUO%wLLIHL7z0RfYOl~jfDu8mI~C^6@L?J;;>6iclBp2{fiF^qS_ zQ9APtAK68#5A|?cGC(;*1x&XU)j59C7ipA8tCgCIquF1|B_wgIw?ItZ{0iF^U;H=6 zk5Cs!B6KF@B1K^Ue zWa``5;b7E>vS~B`jg2B1Oi^h#uu9`~IfW6Se2_s39sJFwCAw4&8e^QQp|-j@*LpT( z*0skQxw!rxUxz%Lkj+?F$9z|+;w-;ex~&gB`s_c{wKT@ywTlnkbBhEXHzJ?kR`9T< zG(clJNgZjB^S}A%II`2EnfhF$>8fJ0Vh}J0zaQ8@y$$4p4UcIA_*#=zWL`ltGcjsnw^G=n~Q#Wy}ga}fXSdN@aZl| zd@4wCD_{5e9o10d!np)yXOpg=^PtSI7iV+TP#QzLuR>7_X#;3&YHjgCn4BsO;!3B` zg!(h!_$cRo5IxKPM(ecO+an3>Gh`WyDPgiwgN>k8@PeV&ErnmebbGoYQbQ&+pl`7}Ux$9(eURt_ z^_$ONdlld89!#8QGZ%Qdac3eH-a8`iq)WG*7et*Gl;t(e7sXLSDfr&bM|Aj{ODQbQ z`_PSE zXdeRIj`<89GyAUNX<$lN1IX-MW2MSRBbf8|<1WNJ{>8?AGhbUzN7z^`<}LIwj6)uj zOxuPxjD|hqH=mykogOLL3_gqlZT>7-asYGYS0mPO2ViSmmPykl9<>Q(BXxusk z_Zl^%{Kt!ql+>I>3To}*{AfEDx1T@fm6|RiWKSm3rU;uTPpoZpCD`GILzM-t4G-5f z!>upbFn*MG@KJ}--x(hnn@prndKoHsik))<#;pA)Lo^;upyz46tBn%A=k5}|*XmEL zJ9}+SV?$Oj%+VI8orq)CQ;)7xzQI5i6kld}dBN_Z{;ALXUX!zEhA+cpPj|f!0S{D@ zjiqmHVRb8bt*e9Q)8QtTfrAcGD*9c?^Lv?%&9ka(yO$jvl77iDeLPDlJwf6m162Ao zEGLdO`PW-{7Hj&3#`z-Wqjn22(bCl)1-{BuQo)}=ba3@lL1$e;W&5G$E3XGieK->N zS>fNuCse2r!cI6}+u3Rs8dzVX{;jPUXs{5u8S^xntRQ6W?p@s55b zNON>>Zrp3ceLl$SbvT6a^GwH9>=A2^AFP)Yx-N2iunF?dw$?Atb;oU)(>K|yyOjF0 zrFnPd{Sdos-}fP#=nmJm+W&jBezl5!7Ax_E84_=WRJSpfc zp0+tyv zGFGFu-fydtiO<~QnJ=<#tG4sPN1e zCDmIOEo&d^eJFBtKD>##;P8D}s~q3Qo&?&+_dS@tuHouoG*Mzh8iM?tzBa#*ENuj} zZCUX!HvUEb4dkguXGm|zW^L7oqKnCde#F;|mT2eBEl^Su`xNAFj1!o&? z-V0h9OIbESL|indH)J|Ei>)pj4`pB6TR`j(_1VnIjIULSFVuV-Gyt=2M!Z z^HaM!ADZLesb3pyScB%cvFqiBh95Y~nfC};?b0=P2N@l-ew?>iS-_{YUm=_R$qssr z+HP9lAq>;gL6{zID#!o|_n4vcZznno=Xz-+a?|9s(a} z1Q3DX;YO{glX(M)&&0wRUFF|u5n0TD3D|q#w{f1R?INCfwDn<2C#vnXNbF1Arf=MB zBkLPYGd>S>l)eQBwdF%6v1$r!si#fOd$)oRoU^EX%Z5f+3hwmD@0Wmw)f?E`3Z=E+ zJz{lF+r{Ji`_`(uM%1+Lu-+QO>NI*20!N61t}iX(-lAqreeqc17hoZI&vS0)JfZ5O zoVWLyR`gj{-eb1$>mdhhgNKM)J#D7(nj&M$AdP zp0CaJQ-k(x2!T}a9!+0E@iKE;j@?`RvPiUgP3B>4+`0UCEMAe?$^KHY~Itn zJKhbrYJ+zjvRYCm`$J*#;^z9En>*9oQhBI{Akud8vm& zf67Ye+bbh<4sXr^OY>-|iD)kK4rmCpyzg&f|9>yNWP=B^tIXDO}{1%3O(Llfw z*gE}{$7XfH(6u#Sbw=QUJZns&Qo)|YO|E;E#g1-Fa}pzm!jK>K``;W5umG;BTK<|4 zaL2ebqDzm-CD%l%rTK^ojEOWqbW9vvj}7vpX1$J<2gTuQWPA`iUCVnuw>>}eH5pmp z8KTxu+2a$Af~sHK_uL!Og(?p_Eh&(q>oT)+w1kpK5wK?WIEF*ATV5mAjf(Z)U!-Da z57*gxMJ+sSXU%b)zR6P!aUrpb7oxDIirgeO-%CP3*D=6~p|fZ*)ob}aCBU72N`LWz zm#Nrm%(jW^U5T~cjm*P!dJmpMGo)J=2Zu?X-E|Bk{LuZ|i9VdWi_f`UK@&c)!v9pT zYj@yKRHn%A(-)D}^DwE6%3lL>JU@JP(PEo;DIC{+J6>o~wJ$JmQOnNOnT@xN>WJAp z>eR@gwZQfrSM)Y>oHK?tUSzA)g<>E(OU!8(F!7fH)m;4KZ1{fUnvzn z?=B;a`krr{QSSoxo`>e1JHW=nB(y6;!$T)%UIx4bNLm{kmA4zN4mu+#vY$11@yGjJtoxgA2{QNieews5!DE zhw6mWg3-epzp=-460|->{RNPPQtUvbsC;LN=oxwVo73MM>5$o`vl2C93Ee`iuySWT z?NNjt2x{hxR84A#AhNIs@<%B4U`D^SGQlIfOba z9zEi_u=0#)x!6wGaXqA>^K~SmqZRTD5{d{iFTN%SUwn70Yw#rEut+W$3cmUMGZ6Qv zZ>O?k*F{lL;bQEGG9~xYWb%}_(D&~l<@5dfl~w+^$E%>(uAqhTz(3~ujDi})Q3TN* zn<|F9Vk|IkWZYYZ6Ha$revDQNB z^ZVziV+~0BAMbgS*nZUvG>bmP-OE=tFFAz5Qw)0@%IfAH4_ht`#p1S&g{2nz2I!E& z1vuFN*di+MlKw3YwBp$E1tf@$|6B zH?=_y!1fP9f#O7YvzD^%&fhmV(G`z&>s1G;3rf-`uc}aVpAp0{yRd<mH|jb-eso#=d3Gr%pYtzB@q$3+R}Jor?uJTXkhOuVm2}XDE=kT(KEaS9gtEmz#?u4n7OMqaXO!_aKwYfl zc-|R3f9QL{3a48{GlZbpnFaPzHQWUH2!@EZdy^F7M4Ll?;?D%zU zx8XPVNm>r?yGryBie-U4QC7Qozl^<+THUst_~Uw}^O;O?5`poD4+AWll@|+2TLULq zI?TueG$P4`cGf6^F7M`C;j|^IT#QCznhpKiF}=CbrLR+)j$kt?hF`D0oi0fGP9|tB zK!El>ZpV}`^+}JLC2o62WI9gBm?`g6q+1XYp9-$!Ut@3=nZ=zIXiT>%FM*Xw=767* z*00KWwLRqlM{7>CDKj^Cf-o1|5^$QQNyM&)-xk z`<9ES^NR7l^>g9HC=3MB@2lU5rMvrq%Oesfgxg>p$Lv0a(ky;|Nc-SR>5?Xsn1B=y zaDt!)pAQ?~;TQeQBjC9jqOCDqym_+PROIr8F}>-Mn?LmK(!&(nU!^lmo$^HYdC9az zV%?LiN(Zfzai%Aj!0b3b=-xR;jdiB5PAM_!<{;t>d`v;NP8}7453i?Nva}r zE}>u}X3GazpP9l>KBIY8jsMOQvQ%s$T&zw7+7jBXHq0$0BV%u?OLLx|;Z*@z1&*aD z%GM{f7UX%vbpLiBw71QY>R=AX)88E0f=|);h>AWaEw$pMI9XOpAea^~(hAVc9dZ6< z#>uH`jBA0@;S~LAt+6B&b1$jU>ivlJJdEAzdewWA$NE0%)4Ot|`&cvZ@PoFXH765DLHw%*1wTrebhwZ@aC}&(5kU2zqxxoaUi$cO7Q6$i^1|xJrBST>MrYiT} zAyJ(o2nvd!aU*?a{4l6=|7`eb)+XLO$Z%YucY45lKV27;4%Miw1JE$<&D^0%r~|<> zKayLI&;n0hbPW#gk*F%NQ}P_Co`xCE&zoj$Pd6wcKECf!Hjs3Xo&D+l+pn~WF)@aT z6eXrEanALr(D3j)Akrlqjc~tuchO+s`PX+gtj-vqvs4g222N}^j_)T6aIph{O2BZzx%^1;YROW*A6jCR%>+!HW4>VqH=$)sFN5HeWHG zwc7ocQ2kRNT{&Jva2zM@*MNK?LD9#l#aH$%VXC0-TW^WKFVOSec+n+J=v5p4$OzQ+ zluy5tTEFo9yH@)$@o=#h(mkc9q5#|Qku3I0#)5J$rJ&5024boN z@3hu9qEi>R-rD`A@%837+dE|d+_x_Xg*E#HhT z{}N9bWvP(}p3RlS)b-(S{uhiO#%4EBHQ;PYH&#ppgQ zRy=%c_Y?m91xgZY&EKz8!~`e0SVL`$LPsgBfhXp(XMIlp$ekf@u8%(BrRst4QP|`; zDq6yj&4>k9#)DSw9duCVh*c0Ry>U8B14G2wnH&z)GgqrE-q2RL4!mE}t`4n_%rqsJ z@+henpxXlOV^F=^+L8baCr(Pw2;$*q#5>ceS%>yrQQ_4se_ZFPkfZ0DAtxef^}524 zx*ps3VQkxfGtyJit76C+s@XGU^OG}D76FMy^l*koB{WdZ=>;)gpoW=U?-iMr!RGMnY5w|8fBFECK+Whrzuye^k2fJuqcBmV^zD#N%UD10WpbAP|2}_AlVvAs)m0{wgq<9 zmwxoNFMzZ_nS5Lfnkcb#Ij{MA8d5EVVaw^ ztGljb^V+8#&tsDD;qS8ubH;a58cW?`N-Hn-LKzF^m>p~uo8T*oXh+`#*D$3Os=?`v zX&cipy)4I7b!#LlyaNKuyn(Qf)+#j=W^yTEf;T_0b;xDz>i@C{1&z|G!O9VNF3zw+ zrU==4pt9WP<#K7d2h50;Xk(m7sL?1E(Sj%Kv10#1f0~Z>^+x?wUvoIhk^xJppzNqV zK?y{?86g8;5VRn?70%e`^gi1m zv4w#lNBURc+<>GRf+Jzh_U4tbtX%pXBv*J$SW%EVyhUi5cMk}Y8mZH$M)N(`a9Q9Y zEFp!}05_wVy*tT)p&=Uf079Q5?L(gMwH!qWMP>c#HFlrsufzN1)pbz$u!egZD7H8& zlU#5RD+XTuRnb~0F#pKkEB_GGAv^+f`&(MoweBy(3_Qui0=+VoXG_wuJ3`5&MW~KT($QfBk4^DGVyZV;cMQY(eM3C{dZ%!rVY`nV~qSB)#&x7Q98Y zp+IRi6e@~wht(2O#@1L-mg7>EBeoqIOY+A;D#imj&?6o~CZ$Cs>*s3qaS;TC&KdHc zv%1hiaHEA~G2$DZCUO=Im6xl-o_+R@dg^`HIy1DT6z*9=JX%K52tVtqA4!iG1k1UY zm+R6ae#Xwng*V;f!|xD5I{g<#06|M+8IZy0!5SO~#0v%{EGw%@3u``V_z`KmZZv&F z^+D|oNKwfaS=)b;*56h`w-nB(&`Ood;*euolYXIG`;Fc$=sGr<6$t=dZH+uispCf3 zVdn#~-cH-FkWoIH%g>N|9^I$B7=9QTp1puMEk-6(D{8p>AhwLUziN0wFsx3Qw=6KJ zulZj8B{pUS*@a(~imk!}Ht+A8UD`b+k zgeBeU(ncjoJ9Mdb*FU(c{#`Vde{Yc2j)}9S7@3ffqphd^etcCEK6Xi3WFPTc zPBoE+Lkp+}UMvTL`Vi0I7m5OynvHOO#@6AFbhr+)Q_Vdvm9_rFdp$<56B~Bb)`Kdx zMkqHSK#AYUlopOlO7pbj|a!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8X6a5n0T@z%2~Ij105p zNH8!kMrMXYltlRYSS9D@>LsS+C#C9DVstT4fPE4;bsH1+JHo@{EISEfi{E8 zw==W>t3(ll+GC>+vK+}V5TAlYfnK%aveAbJn;nw>Ri$!n(%;y<|W>?l@bHIEYi$98b4#)>Op zL8`vXH)i?-pHz9dW#&asqn-DPPlrTr4zMXm+wpwfcgyGVswKtS{u?}v-|{!>uW7@P zo{jdeWEsCy*-nsO|D-$iyL)|uet-z;laS7&CoD_89;;$3&p*5P(^eftk?GGW=bd=` z=kX_@`h7p9NVl54v)I=2bH4sjrSp8OKfh{zNbeU!3Q~N%*XQ* zuirYlU|qAbqlQS^?K0OhZr@IY9!X-->sv8t#yRKMlym8UXZ025n+KRn8)U1gEmsfJ z41ZFmv4S&^<>Z+@7LFzdZe_#BlLjAtUA3->_}Su{%$$4i-*z|QzS{@qr6$g2pAda= zVc6PJHC2s4o@*y)GO}&I?PxpEDbRnxl{Am}636+j2Xv?hTzT|iSL~KGwln?j$}{?? z1YahULuF&@*-G6}7%KUtGb`@v!0KZUI?=wYqIzo;~Ge zxx@BmTJOszo;>|LoxAV5ZNBG{k-#wVqKe*`*rrvh7D#$9JbWR+zMXN3w`xS1s9$zG z&kbh-8AlVdj)_M^jvYImQfmKSpg=}x^RJpel|PTV$nQVHUsSd1kw<&Bl+n+8!}zbl YOP1^QuW64t1Nr)NS$TDW^R2WNkgNiI!vz16>4_Ts; zC1uGL8Iry1#>?|OzvuV9=kqz|+~+#ieO>o`{yVYPO!S!O`RD-vU^39xF+161PA47c zWVNQ;i#ge-UA2w10iZgW;n0!hL(Xxu=+Rf0Kfn~ofN?1Y#sohxPh@i`XY^u;An48X-6k-l(Tf8C-#I50P2D8 zlhD)I*AWuv>EVTk2Wp7?#ekp0r!Y(e@)yPTwuT7O_!{JjH_jQND6JqZBce$Ufk4!8 zPA+gW9mGHBCnpUNH(y^Y90m&r2#^ktm-fcF!emudRbeu6FgZD?6NVH%$jjF;P|6Dr z{afV!bab5YXdDLXi}Ch?oa#EFy#0JNL_|)F{vChU>5Fmse z{?$H7RX;`HrZ|lAiSwzxrmXs3%>Tju@ll7Jn*UcZe|P#9deW*Uy*ljQXVauN>JYyH z0E`j_I@%U)G%Lt6*z_N~cekfL=CpZ9gYUEA#i>)S_CtC&h&Ekuc_QOn&E3JZIoBta zEP8m$N0_YyJy$GpY@YWo22xU4QM1jn5(I=JQ&QBjjQ!JE0uGv|7f5p9K)+1?x-t1k z`IvmX)AH#+b8V}2`b9i$Mo<0sCDg=&rAL76FFO0UwqiQlJX-1Ni^9Tl>oFx5dm42pGR&l|fo{u+(SXSB{%fgBZb6(ij z7`QZhn1sR{m8Q^C(46A8Yqrs@xuKMH{U)45VFD{XlZpt@O+_FM)Y0yC-_=BA#*>7X z{h;a`sFAyP_1+D^T8hDPSEMR(p4!(1~c1^NC@Ng z3qYav&HEjE&q8O|EG(0>F$S89jjY?DEi|y!CW=Ca_+&kU5dXZbJP!5=n=Jn80qa0x zQ+AJdS{IF0IxT^c;zG~0XqRRz`O=G)xF*cutCw=~P7_2v*N&=m$AJ*FYM)6PnM3-; zu?3~W@VVbzifi}k$mZWPJV8kfIi)Wu2u&q74RX5NqkEmKv@8^;jV#zrtHVf0cK4aj znGSyR>Q&o>9iQW&iE9?N5uGZ~%`Ityz22=&pWB8?t&^=Z<|Jt?6z(OiKhpx!2G66w zs>oFl7V3|;<2u|HT*;AU>84q+vS6|N(jpF3=qBr}#JPxuPzxk44NX|gfMf@r+NF?! zNsk5nXYS3FD>Xt%PJ+*(>3+R6;4fqYxje`v%Kv22&nt14sIbJ7*u%&P9D=N2TylEB zpvuP@{A!wk3}buH0r*9V{#6U#h8650BVEu@;N}Y$px*5|w$b(^*I_hm2Itp4{WT_U zx&$X~2q5@^UaiX5ew31^$6e$rXAz#=^q_9h^xbJRFxI%}BLA$HtH?e#D%XoUJjPLm z`SH`fPXx*o>Jfh93^_kgUCV*#IZ?4TcUfVz;iM`1OFx-~w2x-5Ak|;fM-{!T`s@^# z)8jzz2OV)CD4yqasj=g&94C}A&q>Dly!{i;N)KX7fwF4J%;>S;-!J(V)YNiLPHMPK zPe<-X>O7F=;|Hm+&}n%+?JxaQkjn1#=vLJB7p|f)!8qm(D~8I3ZE>DI11(i0YAG44 zEDY^Sj3CWYLb$8!WB1BtedcQ-L5ZqtB40&kMK#V1u~kBM&Op4qh2U_yqUT^JB4I`# zd+j2601kalSlxl{IN zgv6mw)mPd`U~zMI`lR0@`$&lPjZJbU0~e|z(nluC=x0F7=CiY6Ls9|>c~75mH3i%u z935=WBGF(ud3nyG?O$W@QpXb}wP(!yj6Q(5e$8_@5| z$PCkS8+aYk8a3!tMDoD;H)2ccm}6rN+&q`Ur20F8MG!*fy;2RVb7s%H-pL0A1(gb@ zfkd5)M_=#or&}i#ZlM(~PfAATDD=~5tqybaPAqq2RGYu^mM^c^xz5f%ssYcuuT5jo z79HW(*(H8qyxKw@=HZ6HTqzljlD1|6+oX4Qt3xL1Uv}|{OLj7wS#6>}t-9|X-tFw^ zDy(Z|w!a7S;L0ajId_(W=Mn$~`X~a$uiZ_Cz@~%sAKbU{%gQplGXi-Q@0|C3DNIqQ z<%Q43-g|>aoeK^Q9-JCvPVOPRn&%MnyC0@2k};od?QHeN6GS*`kUrZTEoP|1{7R#WiDCynUIgu*ZADUHSEk=Xobn+#-`naYFs$WvPf*2@R!A>8enri!9z08 zT$CBp3!CDC>P$P+ikXbanhl{A4X(5cAEow*N8sxe3kz#kII>KRNgpf=j=hM=w~`sS z`if0ZFot2)+16MZ!?^TNYZCcb7t<+Y@TId;hmQ+kezk_uD<7Vj@eaqsBTBw66K|ic zD(rr4}?5w zCWgb+Zew!uj~>qb;1+5(PrgJQ5-r$O9Od5Y(5}+w0-XvaH{1n>h2-7^MS;chebzJ& zLw*P%?@nJ(`Ti@RlD8%ItlyK-yuqzq!lB$bpd$b(o<^NMF7dL|`GxI9^Fi9dy;S48O z3~EHP@3mz$Z%;ICs4W*@Gu$S&vW@W%_)sMZQ|LPhr9UP{0g}(69>})4v_I3mx-nk( zM!R_`;V>308_+9f^!#y;zV58LO|tl^O_cTVE|0)dmCtwTn3m?=V~+?svx71B5)Z6j zAli2~cr5MD2!<=yl#I9dOS#u8llNNQL?kMTo-;)Fq;!-hT_#a!b%;TQ&!15(WVqJk zDR0)GxBh3Zo`olN!g?|mMkXsr{zewrJ$!E{5K%Epr%B!gU(D90l6*h2z>&*X2Ns5j znLfTRx<#5DixEPMysAh^Pm6H~P##yh^Pz*MBVxik>aAl;@}6^DXK00zHV2`-`vw%! zJiMGJaiOAKa71z+L^k`e|vhL zw%ar(Qu0N1*t3gu9~s{?KVQd}aNgWK2fGhhH%;#{3SyLm85dCIqf%yq+7 ztGp=22U9(tDo3vREiG?tYM6@$1U`4exI4GdIr#3We8^B{Ddt3v7UQ0@H;AGxPuC<0 zUtj!f&|xHzpQh9ZAIH|$am8fJ=q9Mh)Zy?A_ zyKLz1Rhc^HyE^3d{ILm`$+)9d5v2Bn8~7p2$wWl9mZ@R3u@Y^@%-{)uZDyzN(ciTo#KA@yW@_v{K^+o^Sy|K?YP%5KQ~4T#5F(h zx5b_}IpTVsHn(naL_EesyOY)?u}R!_u>h%_Of!8~1Plu-kC$&31-N_G#I24lUH;i; UGQG=NdHVe_&^6JiyzCJ1AA?wWoB#j- literal 0 HcmV?d00001 diff --git a/manifest.json b/manifest.json index cb430a1..a9fa31d 100644 --- a/manifest.json +++ b/manifest.json @@ -13,6 +13,11 @@ "activeTab", "background", "storage", - "https://*.atlassian.net/*" - ] + "https://ellation.atlassian.net/*" + ], + "icons": { + "16": "icon16.png", + "48": "icon48.png", + "128": "icon128.png" + } } diff --git a/webpack.config.js b/webpack.config.js index bf38f41..58dee0a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -39,7 +39,10 @@ module.exports = { { from: 'manifest.json', to: 'manifest.json', - } + }, + { + from: 'assets', + }, ]) ], }; From acf58941f4a5bf2211fba41a09c509d551485940 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 8 Dec 2017 11:20:19 +0200 Subject: [PATCH 07/17] Change icon --- assets/icon128.png | Bin 15915 -> 29770 bytes assets/icon16.png | Bin 1051 -> 1303 bytes assets/icon48.png | Bin 3607 -> 5703 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/icon128.png b/assets/icon128.png index 525fe66b8266f0738ce7c7e0b5a340aaa4ae7f67..c6ecaa7a8711be6a438fd290d3afacd0cd472417 100644 GIT binary patch delta 29598 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 delta 15633 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 Pn*mC4>aumx7UBN`h7m0_ diff --git a/assets/icon16.png b/assets/icon16.png index 624a8890b41da04f1d607ae97195e7f36c822746..0ea6df0f5b1ae57636459abbf61fa79cc82743ec 100644 GIT binary patch delta 905 zcmV;419tqI2$u?wBnkm@Qb$4nuFf3kv0Z!te*;%ZL_t(I5lvD}ZyQwC?7Gf=>|(EPJ|GR ziivQQxH1W*@mD8fdp>N>_+!S8c|(J^i+AtS%suDa^Dgke*xK6S*;UiDnZGMfN{{yU zf9c&jpAQfAf1~wEC3p5KrIei2+*!f$;o%`=`JnjdQ?;cn9+k@Dp4#!0AD698OMYu_ zH-D3T-`Ux5iCFDn2a9|@?@6cARxX#j-j=2Jnr789dOf})%cN&cKsYZ1!JBC`8rei5 zVK5a=(Ek87H#c4O%5nLY(e0vsQk{6be3C!P8n5W;xZk&DD@Tv7JAB_iQ(?IP z&(Q2*u^7pIbMMM&vyP?JH9meZNyA~0TwY!TB_3KV>_KZQ*BAh>%Y^?sLN=RaUf9RS z$MYQFVoR$p*=y@d@v zW6Pj>4|Y*&N@(dr{FwU*H{M<%+xZ;?g281+vFP+pm~wZ7a=GjRO!@tn%z=q}Uw=mr z4vumAV?R<0>+qUwq-NK+FFw0NQ^^-*OU2TH1MoXj?gBKMP1is{2(NZ^1FZSRJ8zOw zaSy*dEaB?P3|@WZD!kqRJ*n2of8v7TWAa(J0GUk2W|s-L7cHlHZGDb(Ix1>UWgH!y zV48a!p7|80Cq(1VJrADuxqHAyXC5&5&N$RN91NmDAOzkYBdV$(B#OAavVu@Bgol3| z65X&Tf*`;!^bZ)JEX$O0*4H)i=RzrJ8vVF69zqZ!q}q_6YdWZ9pin44e^Ct#O`WS( z|3atLy7^#xdu?N5!{*LjKx_W_i9Ip{y3(@DzK#p=6qK&vyu>L8?*;GS5DcE<#>3%g zJho7ir1zN$cYVM5^6tBa*8Naw)F$@C<_5ztiACcG_@~hA>fksImSy2WERNA=%*j#% zgz#*kKLJbYe~U fectJr_(%T$oExO7z3x9y00000NkvXXu0mjf=hMVx delta 651 zcmV;60(AYC3Y!R!Bsm0UK}|sb0I`n?{9y$E001CkNK#Dz0D2|>0Dy!50Qvv`0D$NK z0Cg|`0P0`>06Lfe02gqax=}o_E_?xh0xU^HK~y*qrIJl+6Hyd~-#eMfSCc9IjQuc} z(uJBJXuyIy-MY|CL3Hav@E7Ky^}dOeUIujGq=UH3{tTV&nv*^~QPucW=$3^0h1>6qn|Cp2*|;!{QfPrw>A-08JbQH z_wGM{rfIT6Mx=w`a6EbR5W^9F;A|!X$8KTQ+Qp!*gF`_m6o%V&Ma)L_%2mW-0xpiI zl9f1PFpa3nMXE$uRKx)jNDx z`Giel18vd%w?-3=+rge?VV?((TgjnTt;&3Qfl^7WkSPHMx7$HIkwQ^_PoUIhNS_$T z4%bkKCs5Sl@VZ^JtUZ}e-5&u=Bva5e;8e%LR_-${r&E|cm&V-81kBY{%zm#SD)xiX zs04`NfXTZM9T2T8hVZTh>^q;#>U5FbwB?Qa2z7D`h5I(`Nc#ZzswJE ldZyw?hie)#`EM~_^%JD0EsO`f)}sIb002ovPDHLkV1g7kDY*au diff --git a/assets/icon48.png b/assets/icon48.png index c62ad861bd8c4473a2872e8ad055d4d5f892912c..16fff192f1ed1ab0b2ad6f393ee225b6ee4fff28 100644 GIT binary patch delta 5340 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 Date: Tue, 27 Mar 2018 12:33:10 +0300 Subject: [PATCH 08/17] Add popup with 2 buttons --- index.js | 12 +++++++++--- manifest.json | 7 ++++--- updateJiraBoard.js | 6 ++++++ view/index.html | 4 +--- view/popup.html | 11 +++++++++++ webpack.config.js | 5 +++++ 6 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 updateJiraBoard.js create mode 100644 view/popup.html diff --git a/index.js b/index.js index d158b69..dd2d1a5 100644 --- a/index.js +++ b/index.js @@ -3,8 +3,9 @@ import {PageController} from './lib/PageController'; import {SimpleTemplateDriver} from './lib/SimpleTemplateDriver'; import {JiraApiClient} from './lib/JiraApiClient'; import {ChromePluginConfig} from './lib/ChromePluginConfig'; +import updateJiraBoard from './updateJiraBoard'; -chrome.browserAction.onClicked.addListener(() => { +function generateTemplate() { chrome.tabs.getSelected(null, function (tab) { const controller = new PageController(chrome.tabs, tab.id); const reader = new MetadataReader(controller); @@ -86,5 +87,10 @@ chrome.browserAction.onClicked.addListener(() => { updateJiraTicket, ]); }); - }); -}); + }) +}; + +console.log('index add event listeners - '); + +document.getElementById('geenerate_template').addEventListener('click', generateTemplate); +document.getElementById('update_jira_board').addEventListener('click', updateJiraBoard); diff --git a/manifest.json b/manifest.json index 84b14ba..e06da45 100644 --- a/manifest.json +++ b/manifest.json @@ -3,10 +3,11 @@ "name": "Merge assistant", "description": "This extension creates merge commit for you", "version": "1.0", - "background": { - "page": "index.html" + "browser_action": { + "default_title": "Git Merger", + "default_icon": "icon128.png", + "default_popup": "popup.html" }, - "browser_action": {}, "options_page": "options.html", "permissions": [ "tabs", diff --git a/updateJiraBoard.js b/updateJiraBoard.js new file mode 100644 index 0000000..391332c --- /dev/null +++ b/updateJiraBoard.js @@ -0,0 +1,6 @@ + +function updateJiraBoard() { + console.log('update jira board - ') +} + +export default updateJiraBoard; diff --git a/view/index.html b/view/index.html index 1d0a047..7784319 100644 --- a/view/index.html +++ b/view/index.html @@ -3,7 +3,5 @@ GIT MERGE - - - + diff --git a/view/popup.html b/view/popup.html new file mode 100644 index 0000000..afa70eb --- /dev/null +++ b/view/popup.html @@ -0,0 +1,11 @@ + + + + GIT MERGE + + + + + + + diff --git a/webpack.config.js b/webpack.config.js index 8596c34..9fe6fc9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -30,6 +30,11 @@ module.exports = { template: 'view/index.html', chunks: ['index'], }), + new HtmlWebpackPlugin({ + filename: 'popup.html', + template: 'view/popup.html', + chunks: ['popup'], + }), new HtmlWebpackPlugin({ filename: 'options.html', template: 'view/options.html', From d83262eba5ed328d07747e53a05749a1cdc0beda Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 27 Mar 2018 16:29:43 +0300 Subject: [PATCH 09/17] Implement jira-transition tickets based on applied labels --- index.js | 2 -- updateJiraBoard.js | 61 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index dd2d1a5..6494878 100644 --- a/index.js +++ b/index.js @@ -90,7 +90,5 @@ function generateTemplate() { }) }; -console.log('index add event listeners - '); - document.getElementById('geenerate_template').addEventListener('click', generateTemplate); document.getElementById('update_jira_board').addEventListener('click', updateJiraBoard); diff --git a/updateJiraBoard.js b/updateJiraBoard.js index 391332c..d466aa3 100644 --- a/updateJiraBoard.js +++ b/updateJiraBoard.js @@ -1,6 +1,65 @@ +import {ChromePluginConfig} from './lib/ChromePluginConfig'; +import {PageController} from './lib/PageController'; +import {MetadataReader} from './lib/MetadataReader'; +import {JiraApiClient} from './lib/JiraApiClient'; function updateJiraBoard() { - console.log('update jira board - ') + chrome.tabs.getSelected(null, function (tab) { + const controller = new PageController(chrome.tabs, tab.id); + const reader = new MetadataReader(controller); + const pluginConfig = new ChromePluginConfig(chrome.storage); + + pluginConfig.load().then(() => reader.collect({ + labels: { + strategy: 'dom-query', + selector: '.labels.css-truncate', + mapper: e => Array.from(e.children).map(label => label.title), + }, + jiraTicket: { + strategy: 'dom-query', + selector: 'a[href*="atlassian.net/"]', + mapper: e => e.innerHTML.trim(), + } + })).then(data => jiraMoveRequest(data, pluginConfig, controller)); + }) +} + +function jiraMoveRequest({labels, jiraTicket, hasToUpdateJiraTicket}, pluginConfig, controller) { + const boardColumnName = getJiraColumnUsing(labels); + const jiraApi = new JiraApiClient(pluginConfig.get('jiraBase')); + + return jiraTicket ? jiraApi.getTransitions(jiraTicket) + .catch(e => { + throw new Error(`${e.message}. Please ensure "${pluginConfig.get('jiraBase')}" is accessible.`); + }) + .then(response => { + const transitions = response.data.transitions; + const targetColumn = transitions.find(t => new RegExp(boardColumnName, 'i').test(t.name)); + + if (!targetColumn) { + const tNames = transitions.map(t => t.name).join(', '); + + throw new Error(`Couldn't find column matching "${boardColumnName}". Available columns: ${tNames}.`); + } + const {id, name} = targetColumn; + + return jiraApi + .postTransition(jiraTicket, {transition: {id}}) + .then(() => controller.alert(`Ticket ${jiraTicket} successfully moved to ${name}`)); + }) + .catch(e => controller.alert(`Error moving jira ticket: ${e.message}`)) + : Promise.resolve(); +} + +function getJiraColumnUsing(labels) { + for(let element of labels) { + switch (element) { + case 'hold': return 'Open'; //Not started + case 'wip': return 'In Progress'; //In progress + } + } + + return 'Review' //Needs review } export default updateJiraBoard; From 2315e0d8f7c799f6f414197508005d106efa07d4 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 27 Mar 2018 18:21:24 +0300 Subject: [PATCH 10/17] Add styles for buttons --- css/popup.css | 24 ++++++++++++++++++++++++ index.js | 2 ++ view/popup.html | 10 ++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 css/popup.css diff --git a/css/popup.css b/css/popup.css new file mode 100644 index 0000000..f39d615 --- /dev/null +++ b/css/popup.css @@ -0,0 +1,24 @@ +.popup-wrapper { + margin: 0; + overflow: hidden; + min-width: 150px; +} + +.popup { + margin: 0; + overflow: hidden; + min-width: 100px; +} + +.btn { + font-family: Helvetica, Arial, sans-serif; + font-size: 0.85rem; + padding: 0.5rem 1rem; + width: 100%; + height: 50%; + border: 0.07rem solid black; +} + +.btn:hover { + background-color: lightskyblue; +} diff --git a/index.js b/index.js index 6494878..83bb2f7 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,8 @@ import {SimpleTemplateDriver} from './lib/SimpleTemplateDriver'; import {JiraApiClient} from './lib/JiraApiClient'; import {ChromePluginConfig} from './lib/ChromePluginConfig'; import updateJiraBoard from './updateJiraBoard'; +import './css/normalize.css'; +import './css/popup.css'; function generateTemplate() { chrome.tabs.getSelected(null, function (tab) { diff --git a/view/popup.html b/view/popup.html index afa70eb..98c489a 100644 --- a/view/popup.html +++ b/view/popup.html @@ -1,11 +1,13 @@ - + GIT MERGE - - - + + From 602b5f318f7c2f2d2b8be28a1ef8e9a527f3bcca Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 27 Mar 2018 19:52:47 +0300 Subject: [PATCH 11/17] Implement transition configuration on options page --- css/options.css | 2 +- lib/ChromePluginConfig.js | 5 +++++ options.js | 3 +++ updateJiraBoard.js | 15 ++++++--------- view/options.html | 8 ++++++++ 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/css/options.css b/css/options.css index 73e9e05..ce4717f 100644 --- a/css/options.css +++ b/css/options.css @@ -29,7 +29,7 @@ .form-textarea { font-size: 1rem; width: 100%; - height: 10rem; + height: 7rem; } .btn { diff --git a/lib/ChromePluginConfig.js b/lib/ChromePluginConfig.js index 7e031e2..a96448d 100644 --- a/lib/ChromePluginConfig.js +++ b/lib/ChromePluginConfig.js @@ -5,6 +5,11 @@ export const defaultOptions = { userAliases: { userName: 'first.lastName', }, + labelTransitions: { + hold: 'Open', + wip: 'In Progress', + default: 'Review', + } }; export class ChromePluginConfig { diff --git a/options.js b/options.js index 1b93c9b..a1ee426 100644 --- a/options.js +++ b/options.js @@ -9,12 +9,14 @@ function saveOptions() { const boardColumn = document.getElementById('boardColumn').value; const template = document.getElementById('template').value; const userAliases = JSON.parse(document.getElementById('userAliases').value); + const labelTransitions = JSON.parse(document.getElementById('labelTransitions').value); config.set({ jiraBase, boardColumn, template, userAliases, + labelTransitions, }).then(() => { const status = document.getElementById('status'); @@ -32,6 +34,7 @@ function loadOptions() { document.getElementById('boardColumn').value = options.boardColumn; document.getElementById('template').value = options.template; document.getElementById('userAliases').value = JSON.stringify(options.userAliases, null, ' '); + document.getElementById('labelTransitions').value = JSON.stringify(options.labelTransitions, null, ' '); }); } diff --git a/updateJiraBoard.js b/updateJiraBoard.js index d466aa3..d1e0223 100644 --- a/updateJiraBoard.js +++ b/updateJiraBoard.js @@ -25,7 +25,7 @@ function updateJiraBoard() { } function jiraMoveRequest({labels, jiraTicket, hasToUpdateJiraTicket}, pluginConfig, controller) { - const boardColumnName = getJiraColumnUsing(labels); + const boardColumnName = getJiraColumnUsing(labels, pluginConfig); const jiraApi = new JiraApiClient(pluginConfig.get('jiraBase')); return jiraTicket ? jiraApi.getTransitions(jiraTicket) @@ -51,15 +51,12 @@ function jiraMoveRequest({labels, jiraTicket, hasToUpdateJiraTicket}, pluginConf : Promise.resolve(); } -function getJiraColumnUsing(labels) { - for(let element of labels) { - switch (element) { - case 'hold': return 'Open'; //Not started - case 'wip': return 'In Progress'; //In progress - } - } +function getJiraColumnUsing(labels, pluginConfig) { + const transitions = pluginConfig.get('labelTransitions'); + const intersetedKeys = Object.keys(transitions).filter(key => labels.indexOf(key) !== -1); + const [firstIntersectedLabel] = intersetedKeys; - return 'Review' //Needs review + return transitions[firstIntersectedLabel || 'default']; } export default updateJiraBoard; diff --git a/view/options.html b/view/options.html index 2360ed9..c702a0b 100644 --- a/view/options.html +++ b/view/options.html @@ -36,6 +36,14 @@

Merge  Assistant

+
+

Specify transition object keyLabelName: jiraColumn, Possible columns (Open, In Progress, Review, Dev Complete, Ready for QA, Close), don't forget about default Jira column:

+ + +
+
From 9cd074c9cff39ea46fb9eaacb8a9d882d0733b65 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 5 Jul 2019 14:24:26 +0300 Subject: [PATCH 12/17] WIP --- index.js | 2 ++ lib/JiraApiClient.js | 14 ++++++++------ view/popup.html | 7 ++++--- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 83bb2f7..2865b26 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ import {SimpleTemplateDriver} from './lib/SimpleTemplateDriver'; import {JiraApiClient} from './lib/JiraApiClient'; import {ChromePluginConfig} from './lib/ChromePluginConfig'; import updateJiraBoard from './updateJiraBoard'; +import trackTime from './trackTime'; import './css/normalize.css'; import './css/popup.css'; @@ -93,4 +94,5 @@ function generateTemplate() { }; document.getElementById('geenerate_template').addEventListener('click', generateTemplate); +document.getElementById('work_log').addEventListener('click', trackTime); document.getElementById('update_jira_board').addEventListener('click', updateJiraBoard); diff --git a/lib/JiraApiClient.js b/lib/JiraApiClient.js index 62ea752..43fc708 100644 --- a/lib/JiraApiClient.js +++ b/lib/JiraApiClient.js @@ -1,7 +1,7 @@ -import axios from 'axios'; +import axios from "axios"; const ENDPOINTS = { - TRANSACTIONS: '/rest/api/2/issue/:ticketId/transitions', + TRANSACTIONS: "/rest/api/2/issue/:ticketId/transitions" }; export class JiraApiClient { @@ -10,7 +10,7 @@ export class JiraApiClient { */ constructor(apiBase) { this.client = axios.create({ - baseURL: apiBase, + baseURL: apiBase }); } @@ -19,7 +19,7 @@ export class JiraApiClient { * @returns {Promise} */ getTransitions(ticketId) { - const url = this.buildUrl(ENDPOINTS.TRANSACTIONS, {ticketId}); + const url = this.buildUrl(ENDPOINTS.TRANSACTIONS, { ticketId }); return this.client.get(url); } @@ -30,7 +30,7 @@ export class JiraApiClient { * @returns {Promise} */ postTransition(ticketId, params) { - const url = this.buildUrl(ENDPOINTS.TRANSACTIONS, {ticketId}); + const url = this.buildUrl(ENDPOINTS.TRANSACTIONS, { ticketId }); return this.client.post(url, params); } @@ -43,7 +43,9 @@ export class JiraApiClient { buildUrl(resourceUrlTpl, params) { return resourceUrlTpl.replace(/:([^\/]+)/g, (match, paramName) => { if (!params.hasOwnProperty(paramName)) { - throw new Error(`Missing "${paramName}" parameter. Cannot build "${resourceUrlTpl}" resource"`); + throw new Error( + `Missing "${paramName}" parameter. Cannot build "${resourceUrlTpl}" resource"` + ); } const paramValue = params[paramName]; diff --git a/view/popup.html b/view/popup.html index 98c489a..749a01e 100644 --- a/view/popup.html +++ b/view/popup.html @@ -1,11 +1,12 @@ - - GIT MERGE - + + GIT MERGE + From cdca828a7b09928ce67dfc8fb152a592de54957c Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 13 Aug 2019 13:00:51 +0300 Subject: [PATCH 13/17] Implement work log feature --- css/popup.css | 35 ++++++++ index.js | 197 +++++++++++++++++++++++++------------------ lib/JiraApiClient.js | 14 ++- view/popup.html | 23 ++++- workLog.js | 68 +++++++++++++++ 5 files changed, 253 insertions(+), 84 deletions(-) create mode 100644 workLog.js diff --git a/css/popup.css b/css/popup.css index f39d615..2d055c3 100644 --- a/css/popup.css +++ b/css/popup.css @@ -22,3 +22,38 @@ .btn:hover { background-color: lightskyblue; } + +.hide { + display: none; +} + +.show { + display: block; +} + +.work-log-modal { + width: 400px; +} +.input-title { + font-size: 1rem; +} + +.input-text { + font-size: 1rem; + margin-top: 0.5rem; + height: 2rem; + width: 100%; +} + +.track-button { + font-family: Helvetica, Arial, sans-serif; + font-size: 0.85rem; + padding: 0.5rem 1rem; + width: 100%; + border: 0.07rem solid black; + width: 100%; +} + +.track-button:hover { + background-color: lightskyblue; +} diff --git a/index.js b/index.js index 2865b26..2cf23b8 100644 --- a/index.js +++ b/index.js @@ -1,98 +1,131 @@ -import {MetadataReader} from './lib/MetadataReader'; -import {PageController} from './lib/PageController'; -import {SimpleTemplateDriver} from './lib/SimpleTemplateDriver'; -import {JiraApiClient} from './lib/JiraApiClient'; -import {ChromePluginConfig} from './lib/ChromePluginConfig'; -import updateJiraBoard from './updateJiraBoard'; -import trackTime from './trackTime'; -import './css/normalize.css'; -import './css/popup.css'; +import { MetadataReader } from "./lib/MetadataReader"; +import { PageController } from "./lib/PageController"; +import { SimpleTemplateDriver } from "./lib/SimpleTemplateDriver"; +import { JiraApiClient } from "./lib/JiraApiClient"; +import { ChromePluginConfig } from "./lib/ChromePluginConfig"; +import updateJiraBoard from "./updateJiraBoard"; +import workLog from "./workLog"; +import "./css/normalize.css"; +import "./css/popup.css"; function generateTemplate() { - chrome.tabs.getSelected(null, function (tab) { + chrome.tabs.getSelected(null, function(tab) { const controller = new PageController(chrome.tabs, tab.id); const reader = new MetadataReader(controller); const templateDriver = new SimpleTemplateDriver(); const pluginConfig = new ChromePluginConfig(chrome.storage); - pluginConfig.load().then(() => reader.collect({ - reviewers: { - strategy: 'dom-query', - selector: '.js-issue-sidebar-form .css-truncate', - mapper: function (element) { - return Array.from(element.children) - .filter(reviewerParagraph => Boolean(reviewerParagraph.querySelector('.octicon-check'))) - .map(reviewerParagraph => reviewerParagraph.innerText.trim()); - } - }, - jiraTicket: { - strategy: 'dom-query', - selector: 'a[href*="atlassian.net/"]', - mapper: e => e.innerHTML.trim(), - }, - prNumber: { - strategy: 'js-eval', - code: document => document.location.pathname.split("/").pop(), - }, - mergeTitle: { - strategy: 'dom-query', - selector: '#merge_title_field', - mapper: e => e.value, - }, - hasToUpdateJiraTicket: { - strategy: 'js-eval', - code: document => - document.querySelector('a[href*="atlassian.net/"]') && confirm('Do you want to update jira ticket ?'), - } - })).then(data => { - const userAliases = pluginConfig.get('userAliases'); + pluginConfig + .load() + .then(() => + reader.collect({ + reviewers: { + strategy: "dom-query", + selector: ".js-issue-sidebar-form .css-truncate", + mapper: function(element) { + return Array.from(element.children) + .filter(reviewerParagraph => + Boolean(reviewerParagraph.querySelector(".octicon-check")) + ) + .map(reviewerParagraph => reviewerParagraph.innerText.trim()); + } + }, + jiraTicket: { + strategy: "dom-query", + selector: 'a[href*="atlassian.net/"]', + mapper: e => e.innerHTML.trim() + }, + prNumber: { + strategy: "js-eval", + code: document => document.location.pathname.split("/").pop() + }, + mergeTitle: { + strategy: "dom-query", + selector: "#merge_title_field", + mapper: e => e.value + }, + hasToUpdateJiraTicket: { + strategy: "js-eval", + code: document => + document.querySelector('a[href*="atlassian.net/"]') && + confirm("Do you want to update jira ticket ?") + } + }) + ) + .then(data => { + const userAliases = pluginConfig.get("userAliases"); - data.reviewers = data.reviewers.map(reviewer => { - return userAliases[reviewer] || reviewer.toLowerCase(); - }); + data.reviewers = data.reviewers.map(reviewer => { + return userAliases[reviewer] || reviewer.toLowerCase(); + }); - const {jiraTicket, hasToUpdateJiraTicket} = data; - const jiraApi = new JiraApiClient(pluginConfig.get('jiraBase')); - const boardColumnName = pluginConfig.get('boardColumn'); - const commitMessage = templateDriver.renderToString(pluginConfig.get('template'), data); - const mergeTitle = templateDriver.renderToString('{{ title | clear }}', { - title: data.mergeTitle, - }); + const { jiraTicket, hasToUpdateJiraTicket } = data; + const jiraApi = new JiraApiClient(pluginConfig.get("jiraBase")); + const boardColumnName = pluginConfig.get("boardColumn"); + const commitMessage = templateDriver.renderToString( + pluginConfig.get("template"), + data + ); + const mergeTitle = templateDriver.renderToString( + "{{ title | clear }}", + { + title: data.mergeTitle + } + ); - const updateJiraTicket = jiraTicket && hasToUpdateJiraTicket - ? jiraApi - .getTransitions(jiraTicket) - .catch(e => { - throw new Error(`${e.message}. Please ensure "${pluginConfig.get('jiraBase')}" is accessible.`); - }) - .then(response => { - const transitions = response.data.transitions; - const toDevCompleteTransition = transitions.find(t => new RegExp(boardColumnName, 'i').test(t.name)); + const updateJiraTicket = + jiraTicket && hasToUpdateJiraTicket + ? jiraApi + .getTransitions(jiraTicket) + .catch(e => { + throw new Error( + `${e.message}. Please ensure "${pluginConfig.get( + "jiraBase" + )}" is accessible.` + ); + }) + .then(response => { + const transitions = response.data.transitions; + const toDevCompleteTransition = transitions.find(t => + new RegExp(boardColumnName, "i").test(t.name) + ); - if (!toDevCompleteTransition) { - const tNames = transitions.map(t => t.name).join(', '); + if (!toDevCompleteTransition) { + const tNames = transitions.map(t => t.name).join(", "); - throw new Error(`Couldn't find column matching "${boardColumnName}". Available columns: ${tNames}.`); - } + throw new Error( + `Couldn't find column matching "${boardColumnName}". Available columns: ${tNames}.` + ); + } - const {id, name} = toDevCompleteTransition; + const { id, name } = toDevCompleteTransition; - return jiraApi - .postTransition(jiraTicket, {transition: {id}}) - .then(() => controller.alert(`Ticket ${jiraTicket} successfully moved to ${name}`)); - }) - .catch(e => controller.alert(`Error moving jira ticket: ${e.message}`)) - : Promise.resolve(); + return jiraApi + .postTransition(jiraTicket, { transition: { id } }) + .then(() => + controller.alert( + `Ticket ${jiraTicket} successfully moved to ${name}` + ) + ); + }) + .catch(e => + controller.alert(`Error moving jira ticket: ${e.message}`) + ) + : Promise.resolve(); - return Promise.all([ - controller.updateInputValue('#merge_message_field', commitMessage), - controller.updateInputValue('#merge_title_field', mergeTitle), - updateJiraTicket, - ]); - }); - }) -}; + return Promise.all([ + controller.updateInputValue("#merge_message_field", commitMessage), + controller.updateInputValue("#merge_title_field", mergeTitle), + updateJiraTicket + ]); + }); + }); +} -document.getElementById('geenerate_template').addEventListener('click', generateTemplate); -document.getElementById('work_log').addEventListener('click', trackTime); -document.getElementById('update_jira_board').addEventListener('click', updateJiraBoard); +document + .getElementById("geenerate_template") + .addEventListener("click", generateTemplate); +document + .getElementById("update_jira_board") + .addEventListener("click", updateJiraBoard); +document.getElementById("work_log").addEventListener("click", workLog); diff --git a/lib/JiraApiClient.js b/lib/JiraApiClient.js index 43fc708..2b705f0 100644 --- a/lib/JiraApiClient.js +++ b/lib/JiraApiClient.js @@ -1,7 +1,8 @@ import axios from "axios"; const ENDPOINTS = { - TRANSACTIONS: "/rest/api/2/issue/:ticketId/transitions" + TRANSACTIONS: "/rest/api/2/issue/:ticketId/transitions", + WORKLOG: "/rest/api/2/issue/:ticketId/worklog" }; export class JiraApiClient { @@ -35,6 +36,17 @@ export class JiraApiClient { return this.client.post(url, params); } + /** + * @param {String} ticketId + * @param {Object} params + * @returns {Promise} + */ + postAddTime(ticketId, params) { + const url = this.buildUrl(ENDPOINTS.WORKLOG, { ticketId }); + + return this.client.post(url, params); + } + /** * @param {String} resourceUrlTpl * @param {Object} params diff --git a/view/popup.html b/view/popup.html index 749a01e..26555c8 100644 --- a/view/popup.html +++ b/view/popup.html @@ -6,8 +6,29 @@ +
+
+ Time spent + +
+
+ Comment + +
+
diff --git a/workLog.js b/workLog.js new file mode 100644 index 0000000..2459221 --- /dev/null +++ b/workLog.js @@ -0,0 +1,68 @@ +import { ChromePluginConfig } from "./lib/ChromePluginConfig"; +import { PageController } from "./lib/PageController"; +import { MetadataReader } from "./lib/MetadataReader"; +import { JiraApiClient } from "./lib/JiraApiClient"; + +function workLog() { + document.getElementById("work-log-modal").classList.add("show"); + document.getElementById("track-time").addEventListener("click", trackTime); +} + +function trackTime() { + chrome.tabs.getSelected(null, function(tab) { + const controller = new PageController(chrome.tabs, tab.id); + const reader = new MetadataReader(controller); + const pluginConfig = new ChromePluginConfig(chrome.storage); + + pluginConfig + .load() + .then(() => + reader.collect({ + jiraTicket: { + strategy: "dom-query", + selector: 'a[href*="atlassian.net/"]', + mapper: e => e.innerHTML.trim() + } + }) + ) + .then(data => jiraWorkLogRequest(data, pluginConfig, controller)); + }); +} + +function jiraWorkLogRequest({ jiraTicket }, pluginConfig, controller) { + const jiraApi = new JiraApiClient(pluginConfig.get("jiraBase")); + const timeSpent = document.getElementById("work-log-time").value; + const comment = document.getElementById("work-log-comment").value; + const params = { comment, timeSpent }; + + return jiraTicket + ? jiraApi + .postAddTime(jiraTicket, params) + .catch(e => { + throw new Error( + `${e.message}. Please ensure "${pluginConfig.get( + "jiraBase" + )}" is accessible.` + ); + }) + .then(response => { + console.log({ response }); + controller.alert(`Successfully logged time to ticket ${jiraTicket} `); + }) + .catch(e => + controller.alert(`Error adding time to ticket: ${e.message}`) + ) + : Promise.resolve(); +} + +function getJiraColumnUsing(labels, pluginConfig) { + const transitions = pluginConfig.get("labelTransitions"); + const intersetedKeys = Object.keys(transitions).filter( + key => labels.indexOf(key) !== -1 + ); + const [firstIntersectedLabel] = intersetedKeys; + + return transitions[firstIntersectedLabel || "default"]; +} + +export default workLog; From e4e0ae5ab211d5e5e630f6e8a9f8282e88b33d62 Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 9 Jun 2021 14:20:07 +0300 Subject: [PATCH 14/17] Use var for jiraBase instead of hardcoded value --- index.js | 47 +++++++++--------- manifest.json | 3 +- updateJiraBoard.js | 117 ++++++++++++++++++++++++++++----------------- workLog.js | 20 ++++---- 4 files changed, 111 insertions(+), 76 deletions(-) diff --git a/index.js b/index.js index 2cf23b8..b15c56a 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,7 @@ import "./css/normalize.css"; import "./css/popup.css"; function generateTemplate() { - chrome.tabs.getSelected(null, function(tab) { + chrome.tabs.getSelected(null, function (tab) { const controller = new PageController(chrome.tabs, tab.id); const reader = new MetadataReader(controller); const templateDriver = new SimpleTemplateDriver(); @@ -22,40 +22,43 @@ function generateTemplate() { reviewers: { strategy: "dom-query", selector: ".js-issue-sidebar-form .css-truncate", - mapper: function(element) { + mapper: function (element) { return Array.from(element.children) - .filter(reviewerParagraph => + .filter((reviewerParagraph) => Boolean(reviewerParagraph.querySelector(".octicon-check")) ) - .map(reviewerParagraph => reviewerParagraph.innerText.trim()); - } + .map((reviewerParagraph) => reviewerParagraph.innerText.trim()); + }, }, jiraTicket: { strategy: "dom-query", - selector: 'a[href*="atlassian.net/"]', - mapper: e => e.innerHTML.trim() + selector: `a[href*=${new JiraApiClient( + pluginConfig.get("jiraBase") + )}]`, + mapper: (e) => e.innerHTML.trim(), }, prNumber: { strategy: "js-eval", - code: document => document.location.pathname.split("/").pop() + code: (document) => document.location.pathname.split("/").pop(), }, mergeTitle: { strategy: "dom-query", selector: "#merge_title_field", - mapper: e => e.value + mapper: (e) => e.value, }, hasToUpdateJiraTicket: { strategy: "js-eval", - code: document => - document.querySelector('a[href*="atlassian.net/"]') && - confirm("Do you want to update jira ticket ?") - } + code: (document) => + document.querySelector( + `a[href*=${new JiraApiClient(pluginConfig.get("jiraBase"))}]` + ) && confirm("Do you want to update jira ticket ?"), + }, }) ) - .then(data => { + .then((data) => { const userAliases = pluginConfig.get("userAliases"); - data.reviewers = data.reviewers.map(reviewer => { + data.reviewers = data.reviewers.map((reviewer) => { return userAliases[reviewer] || reviewer.toLowerCase(); }); @@ -69,7 +72,7 @@ function generateTemplate() { const mergeTitle = templateDriver.renderToString( "{{ title | clear }}", { - title: data.mergeTitle + title: data.mergeTitle, } ); @@ -77,21 +80,21 @@ function generateTemplate() { jiraTicket && hasToUpdateJiraTicket ? jiraApi .getTransitions(jiraTicket) - .catch(e => { + .catch((e) => { throw new Error( `${e.message}. Please ensure "${pluginConfig.get( "jiraBase" )}" is accessible.` ); }) - .then(response => { + .then((response) => { const transitions = response.data.transitions; - const toDevCompleteTransition = transitions.find(t => + const toDevCompleteTransition = transitions.find((t) => new RegExp(boardColumnName, "i").test(t.name) ); if (!toDevCompleteTransition) { - const tNames = transitions.map(t => t.name).join(", "); + const tNames = transitions.map((t) => t.name).join(", "); throw new Error( `Couldn't find column matching "${boardColumnName}". Available columns: ${tNames}.` @@ -108,7 +111,7 @@ function generateTemplate() { ) ); }) - .catch(e => + .catch((e) => controller.alert(`Error moving jira ticket: ${e.message}`) ) : Promise.resolve(); @@ -116,7 +119,7 @@ function generateTemplate() { return Promise.all([ controller.updateInputValue("#merge_message_field", commitMessage), controller.updateInputValue("#merge_title_field", mergeTitle), - updateJiraTicket + updateJiraTicket, ]); }); }); diff --git a/manifest.json b/manifest.json index e06da45..99a684d 100644 --- a/manifest.json +++ b/manifest.json @@ -14,7 +14,8 @@ "activeTab", "background", "storage", - "https://*.atlassian.net/*" + "https://*.atlassian.net/*", + "https://jira.tenkasu.net/*" ], "icons": { "16": "icon128.png", diff --git a/updateJiraBoard.js b/updateJiraBoard.js index d1e0223..b065bb7 100644 --- a/updateJiraBoard.js +++ b/updateJiraBoard.js @@ -1,7 +1,7 @@ -import {ChromePluginConfig} from './lib/ChromePluginConfig'; -import {PageController} from './lib/PageController'; -import {MetadataReader} from './lib/MetadataReader'; -import {JiraApiClient} from './lib/JiraApiClient'; +import { ChromePluginConfig } from "./lib/ChromePluginConfig"; +import { PageController } from "./lib/PageController"; +import { MetadataReader } from "./lib/MetadataReader"; +import { JiraApiClient } from "./lib/JiraApiClient"; function updateJiraBoard() { chrome.tabs.getSelected(null, function (tab) { @@ -9,54 +9,83 @@ function updateJiraBoard() { const reader = new MetadataReader(controller); const pluginConfig = new ChromePluginConfig(chrome.storage); - pluginConfig.load().then(() => reader.collect({ - labels: { - strategy: 'dom-query', - selector: '.labels.css-truncate', - mapper: e => Array.from(e.children).map(label => label.title), - }, - jiraTicket: { - strategy: 'dom-query', - selector: 'a[href*="atlassian.net/"]', - mapper: e => e.innerHTML.trim(), - } - })).then(data => jiraMoveRequest(data, pluginConfig, controller)); - }) + pluginConfig + .load() + .then(() => + reader.collect({ + labels: { + strategy: "dom-query", + selector: ".labels.css-truncate", + mapper: (e) => Array.from(e.children).map((label) => label.title), + }, + jiraTicket: { + strategy: "dom-query", + selector: `a[href*=${new JiraApiClient( + pluginConfig.get("jiraBase") + )}]`, + mapper: (e) => e.innerHTML.trim(), + }, + }) + ) + .then((data) => jiraMoveRequest(data, pluginConfig, controller)); + }); } -function jiraMoveRequest({labels, jiraTicket, hasToUpdateJiraTicket}, pluginConfig, controller) { +function jiraMoveRequest( + { labels, jiraTicket, hasToUpdateJiraTicket }, + pluginConfig, + controller +) { const boardColumnName = getJiraColumnUsing(labels, pluginConfig); - const jiraApi = new JiraApiClient(pluginConfig.get('jiraBase')); - - return jiraTicket ? jiraApi.getTransitions(jiraTicket) - .catch(e => { - throw new Error(`${e.message}. Please ensure "${pluginConfig.get('jiraBase')}" is accessible.`); - }) - .then(response => { - const transitions = response.data.transitions; - const targetColumn = transitions.find(t => new RegExp(boardColumnName, 'i').test(t.name)); - - if (!targetColumn) { - const tNames = transitions.map(t => t.name).join(', '); - - throw new Error(`Couldn't find column matching "${boardColumnName}". Available columns: ${tNames}.`); - } - const {id, name} = targetColumn; - - return jiraApi - .postTransition(jiraTicket, {transition: {id}}) - .then(() => controller.alert(`Ticket ${jiraTicket} successfully moved to ${name}`)); - }) - .catch(e => controller.alert(`Error moving jira ticket: ${e.message}`)) - : Promise.resolve(); + const jiraApi = new JiraApiClient(pluginConfig.get("jiraBase")); + + return jiraTicket + ? jiraApi + .getTransitions(jiraTicket) + .catch((e) => { + throw new Error( + `${e.message}. Please ensure "${pluginConfig.get( + "jiraBase" + )}" is accessible.` + ); + }) + .then((response) => { + const transitions = response.data.transitions; + const targetColumn = transitions.find((t) => + new RegExp(boardColumnName, "i").test(t.name) + ); + + if (!targetColumn) { + const tNames = transitions.map((t) => t.name).join(", "); + + throw new Error( + `Couldn't find column matching "${boardColumnName}". Available columns: ${tNames}.` + ); + } + const { id, name } = targetColumn; + + return jiraApi + .postTransition(jiraTicket, { transition: { id } }) + .then(() => + controller.alert( + `Ticket ${jiraTicket} successfully moved to ${name}` + ) + ); + }) + .catch((e) => + controller.alert(`Error moving jira ticket: ${e.message}`) + ) + : Promise.resolve(); } function getJiraColumnUsing(labels, pluginConfig) { - const transitions = pluginConfig.get('labelTransitions'); - const intersetedKeys = Object.keys(transitions).filter(key => labels.indexOf(key) !== -1); + const transitions = pluginConfig.get("labelTransitions"); + const intersetedKeys = Object.keys(transitions).filter( + (key) => labels.indexOf(key) !== -1 + ); const [firstIntersectedLabel] = intersetedKeys; - return transitions[firstIntersectedLabel || 'default']; + return transitions[firstIntersectedLabel || "default"]; } export default updateJiraBoard; diff --git a/workLog.js b/workLog.js index 2459221..d4def0a 100644 --- a/workLog.js +++ b/workLog.js @@ -9,7 +9,7 @@ function workLog() { } function trackTime() { - chrome.tabs.getSelected(null, function(tab) { + chrome.tabs.getSelected(null, function (tab) { const controller = new PageController(chrome.tabs, tab.id); const reader = new MetadataReader(controller); const pluginConfig = new ChromePluginConfig(chrome.storage); @@ -20,12 +20,14 @@ function trackTime() { reader.collect({ jiraTicket: { strategy: "dom-query", - selector: 'a[href*="atlassian.net/"]', - mapper: e => e.innerHTML.trim() - } + selector: `a[href*=${new JiraApiClient( + pluginConfig.get("jiraBase") + )}]`, + mapper: (e) => e.innerHTML.trim(), + }, }) ) - .then(data => jiraWorkLogRequest(data, pluginConfig, controller)); + .then((data) => jiraWorkLogRequest(data, pluginConfig, controller)); }); } @@ -38,18 +40,18 @@ function jiraWorkLogRequest({ jiraTicket }, pluginConfig, controller) { return jiraTicket ? jiraApi .postAddTime(jiraTicket, params) - .catch(e => { + .catch((e) => { throw new Error( `${e.message}. Please ensure "${pluginConfig.get( "jiraBase" )}" is accessible.` ); }) - .then(response => { + .then((response) => { console.log({ response }); controller.alert(`Successfully logged time to ticket ${jiraTicket} `); }) - .catch(e => + .catch((e) => controller.alert(`Error adding time to ticket: ${e.message}`) ) : Promise.resolve(); @@ -58,7 +60,7 @@ function jiraWorkLogRequest({ jiraTicket }, pluginConfig, controller) { function getJiraColumnUsing(labels, pluginConfig) { const transitions = pluginConfig.get("labelTransitions"); const intersetedKeys = Object.keys(transitions).filter( - key => labels.indexOf(key) !== -1 + (key) => labels.indexOf(key) !== -1 ); const [firstIntersectedLabel] = intersetedKeys; From 0b8ce794464e7da5abae79a9750632bf9711bd9b Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 9 Jun 2021 16:59:52 +0300 Subject: [PATCH 15/17] Not working commit --- index.js | 12 ++++++++---- updateJiraBoard.js | 4 +--- workLog.js | 4 +--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index b15c56a..092ce5d 100644 --- a/index.js +++ b/index.js @@ -32,9 +32,7 @@ function generateTemplate() { }, jiraTicket: { strategy: "dom-query", - selector: `a[href*=${new JiraApiClient( - pluginConfig.get("jiraBase") - )}]`, + selector: `a[href*=${pluginConfig.get("jiraBase")}/]`, mapper: (e) => e.innerHTML.trim(), }, prNumber: { @@ -120,7 +118,13 @@ function generateTemplate() { controller.updateInputValue("#merge_message_field", commitMessage), controller.updateInputValue("#merge_title_field", mergeTitle), updateJiraTicket, - ]); + ]).then((x) => + console.log({ + commitMessage, + mergeTitle, + jiraBase: pluginConfig.get("jiraBase"), + }) + ); }); }); } diff --git a/updateJiraBoard.js b/updateJiraBoard.js index b065bb7..1405fd1 100644 --- a/updateJiraBoard.js +++ b/updateJiraBoard.js @@ -20,9 +20,7 @@ function updateJiraBoard() { }, jiraTicket: { strategy: "dom-query", - selector: `a[href*=${new JiraApiClient( - pluginConfig.get("jiraBase") - )}]`, + selector: `a[href*=${pluginConfig.get("jiraBase")}/]`, mapper: (e) => e.innerHTML.trim(), }, }) diff --git a/workLog.js b/workLog.js index d4def0a..5e7f9f8 100644 --- a/workLog.js +++ b/workLog.js @@ -20,9 +20,7 @@ function trackTime() { reader.collect({ jiraTicket: { strategy: "dom-query", - selector: `a[href*=${new JiraApiClient( - pluginConfig.get("jiraBase") - )}]`, + selector: `a[href*=${pluginConfig.get("jiraBase")}/]`, mapper: (e) => e.innerHTML.trim(), }, }) From a2e5897c2ef825d5b13b05ab002c7b7bf8a5b89f Mon Sep 17 00:00:00 2001 From: Nick Date: Wed, 9 Jun 2021 17:16:07 +0300 Subject: [PATCH 16/17] Fix hardcoded selector for ticketNumber --- index.js | 10 ++-------- updateJiraBoard.js | 2 +- workLog.js | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 092ce5d..2a32764 100644 --- a/index.js +++ b/index.js @@ -32,7 +32,7 @@ function generateTemplate() { }, jiraTicket: { strategy: "dom-query", - selector: `a[href*=${pluginConfig.get("jiraBase")}/]`, + selector: `a[href*="${pluginConfig.get("jiraBase")}/"]`, mapper: (e) => e.innerHTML.trim(), }, prNumber: { @@ -118,13 +118,7 @@ function generateTemplate() { controller.updateInputValue("#merge_message_field", commitMessage), controller.updateInputValue("#merge_title_field", mergeTitle), updateJiraTicket, - ]).then((x) => - console.log({ - commitMessage, - mergeTitle, - jiraBase: pluginConfig.get("jiraBase"), - }) - ); + ]); }); }); } diff --git a/updateJiraBoard.js b/updateJiraBoard.js index 1405fd1..a8dc0e9 100644 --- a/updateJiraBoard.js +++ b/updateJiraBoard.js @@ -20,7 +20,7 @@ function updateJiraBoard() { }, jiraTicket: { strategy: "dom-query", - selector: `a[href*=${pluginConfig.get("jiraBase")}/]`, + selector: `a[href*="${pluginConfig.get("jiraBase")}/"]`, mapper: (e) => e.innerHTML.trim(), }, }) diff --git a/workLog.js b/workLog.js index 5e7f9f8..4af580c 100644 --- a/workLog.js +++ b/workLog.js @@ -20,7 +20,7 @@ function trackTime() { reader.collect({ jiraTicket: { strategy: "dom-query", - selector: `a[href*=${pluginConfig.get("jiraBase")}/]`, + selector: `a[href*="${pluginConfig.get("jiraBase")}/"]`, mapper: (e) => e.innerHTML.trim(), }, }) From a7a5abc4b33c35b2a0ebc06230475792952570ad Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 11 May 2023 11:33:31 +0300 Subject: [PATCH 17/17] Fix wrong reviewers reader --- index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 2a32764..979aff3 100644 --- a/index.js +++ b/index.js @@ -27,7 +27,11 @@ function generateTemplate() { .filter((reviewerParagraph) => Boolean(reviewerParagraph.querySelector(".octicon-check")) ) - .map((reviewerParagraph) => reviewerParagraph.innerText.trim()); + .map( + (reviewerParagraph) => + console.log({ reviewerParagraph }) || + reviewerParagraph.innerText.trim().split("\n")[0] + ); }, }, jiraTicket: { @@ -57,6 +61,8 @@ function generateTemplate() { const userAliases = pluginConfig.get("userAliases"); data.reviewers = data.reviewers.map((reviewer) => { + console.log("---- reviewer", reviewer); + return userAliases[reviewer] || reviewer.toLowerCase(); });