Skip to content

Commit

Permalink
Merge pull request #29 from ljay79/develop
Browse files Browse the repository at this point in the history
Prepare deploy v0.18.0
  • Loading branch information
ljay79 authored Aug 16, 2017
2 parents 5ecbef4 + 7048c96 commit d432690
Show file tree
Hide file tree
Showing 16 changed files with 1,320 additions and 79 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/.project
22 changes: 14 additions & 8 deletions Code.gs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
* - add feature to insert list of tickets (issue overview) based on available Jira filters
*/

var BUILD = 0160;
var LOGGING = true;
var BUILD = 0180;
var LOGGING = false;

/**
* Add a nice menu option for the users.
Expand Down Expand Up @@ -43,9 +43,10 @@ function addMenu() {

// Add "Insert ..." menu with submenu
.addSeparator()
.addSubMenu(SpreadsheetApp.getUi().createMenu('Insert...')
//.addItem('Worklog', 'mySecondFunction')
.addItem('List Issues from Filter', 'dialogIssueFromFilter'))
//.addSubMenu(SpreadsheetApp.getUi().createMenu('Insert...')
.addItem('List Issues from Filter', 'dialogIssueFromFilter')
.addItem('Create Time Report', 'dialogTimesheet')
//)

.addSeparator()
.addItem('Settings', 'dialogSettings')
Expand All @@ -60,7 +61,12 @@ function addMenu() {
* @param values Optional values to pass into format msg
* @return void
*/
function log(format, values, arg1, arg2) {
if(LOGGING == true)
Logger.log(format, values, arg1, arg2);
function log(format, values, arg1, arg2, arg3) {
if(LOGGING !== true) return;

if(arguments.length == 0) {
Logger.log(format);
} else {
Logger.log(format, values, arg1, arg2, arg3);
}
}
19 changes: 16 additions & 3 deletions IssueTable.gs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function IssueTable(sheet, initRange, data) {
// for some custom formatting
switch(true) {
case key.hasOwnProperty('date'):
key.value = key.date;
key.value = (key.date != null) ? key.date : '';
break;
case key.hasOwnProperty('link'):
key.value = '=HYPERLINK("' + key.link + '"; "' + key.value + '")';
Expand All @@ -75,8 +75,17 @@ function IssueTable(sheet, initRange, data) {
.clearNote()
.clearFormat()
.setValues([ values ])
.setNumberFormats([ formats ]);
}
.setNumberFormats([ formats ])
.activate();

// flush sheet
if(i % 5 === 0) {
SpreadsheetApp.flush();
}

issue = null;

}// END: for(data.issues.length)

return this;
};
Expand All @@ -98,6 +107,8 @@ function IssueTable(sheet, initRange, data) {
.clearFormat()
.setValues([ values ])
.setFontWeights([ formats ]);

SpreadsheetApp.flush();

return this;
};
Expand All @@ -115,6 +126,8 @@ function IssueTable(sheet, initRange, data) {
.clearFormat()
.getCell(1,1)
.setValue(summary);

SpreadsheetApp.flush();

return this;
};
Expand Down
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Jira Sheet Tools

[Jira](https://www.atlassian.com/software/jira) is a powerful and well established project management tool amoung small to enterprice businesses. Still we often end up using Google Sheets for some overview roadmaps, project dashboards and other purposes.
[Jira](https://www.atlassian.com/software/jira) is a powerful and well established project management tool amoung small to enterprise businesses. Still we often end up using Google Sheets for some overview roadmaps, project dashboards and other purposes.

With this Google Sheet Add-on the, called "[Jira Sheet Tools](https://chrome.google.com/webstore/detail/jira-sheet-tools/ncijnapilmmnebhbdanhkbbofofcniao)" available in the Google Add-On store from within Google Sheet, you can now take your sheets with Jira information to the next level.

[Jira Sheet Tools](https://chrome.google.com/webstore/detail/jira-sheet-tools/ncijnapilmmnebhbdanhkbbofofcniao) allows you to visualize the status of any Jira ticket you mention in a sheet.
You can directly import entire issue lists with your Jira filters just from within Google sheet.
NEW! You can create time reports for any of your users based on the Jira worklogs.

Enter your Jira server domain and user details once, and be able to use the Jira features in any sheet at any time.
No manual status update copy&paste anymore.
Expand Down Expand Up @@ -64,10 +65,19 @@ Even when used within text it will search for keys and add the status.
If Jira issue key used in a single cell, the value will be linked automatically to the Jira issue page.

### List Issues From Filter
“Add-ons" > “Jira Sheet Tools” > "Insert...” > "List Issues from Filter"
“Add-ons" > “Jira Sheet Tools” > "List Issues from Filter"

Allows you to add a table/list of all found Jira issues based on a Jira Filter.
The dialog will let you choose from all your Jira filters and then insert all results into the active Google sheet.
You can even decide which information to be shown in the resulting table.
Most common Jira fields / columns are available to select from.

> Note: This feature is currently limited to list a maximum of 1000 jira issues.
### Time Sheet
“Add-ons" > “Jira Sheet Tools” > "Time Sheet"

Lets you pick a user from Jira and a date period to filter for and generates a nice Time sheet report based on all worklogs for the filtered user and date period.
Supports two different time report formats; "1d 7h 59m" for better readibility or "7.5" (work hours as decimal number) for better calculations in the sheet.

> Careful when selecting to big date periods, can be slow and become a wide table. Start with 1 week and scale up.
2 changes: 1 addition & 1 deletion dialogAbout.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<div class="block head">
<span class="icon"><img src="https://s3.eu-central-1.amazonaws.com/jira-tools/symbol.png" width="50" height="50" /></span>
<span class="title">Jira Sheet Tools v0.16.0</span>
<span class="title">Jira Sheet Tools v0.18.0</span>
</div>

<div class="block about">
Expand Down
42 changes: 28 additions & 14 deletions dialogSettings.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,34 @@
<div id="response-message" class="error-container" role="dialog"></div>

<form id="settings" action="" method="post">
<div class="form-group block">
<label for="jira-url">Jira URL</label>
<span class="inline grey">(https://YOURCOMPANY.atlassian.net/)</span>
<input type="text" id="jira-url" name="jira_url" class="block" style="width:100%" value="<?= url ?>">
</div>
<div class="form-group block">
<label for="jira-username">Username</label>
<span class="inline grey">(Atlassian account name)</span>
<input type="text" id="jira-username" name="jira_username" class="block" style="width:100%" value="<?= username ?>" />
</div>
<div class="form-group block">
<label for="jira-password">Password</label>
<input type="password" id="jira-password" name="jira_password" class="block" style="width:100%" value="<?= password ?>">
</div>
<fieldset class="block">
<legend>General</legend>

<div class="form-group block">
<label for="jira-url">Jira URL</label>
<span class="inline grey">(https://YOURCOMPANY.atlassian.net/)</span>
<input type="text" id="jira-url" name="jira_url" class="block" style="width:100%" value="<?= url ?>">
</div>
<div class="form-group block">
<label for="jira-username">Username</label>
<span class="inline grey">(Atlassian account name)</span>
<input type="text" id="jira-username" name="jira_username" class="block" style="width:100%" value="<?= username ?>" />
</div>
<div class="form-group block">
<label for="jira-password">Password</label>
<input type="password" id="jira-password" name="jira_password" class="block" style="width:100%" value="<?= password ?>">
</div>
</fieldset>

<fieldset class="block">
<legend>Time Sheet</legend>

<div class="form-group block">
<label for="ts-workhours" class="block">Working hours per day</label>
<input type="number" id="ts-workhours" name="ts_workhours" style="display:inline-block;width:16%" min="1" step=".1" value="<?= workhours ?>">
<span class="inline">h</span>
</div>
</fieldset>

<div class="block">
<button type="submit" class="action" disabled>Save</button>
Expand Down
173 changes: 173 additions & 0 deletions dialogTimesheet.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/pikaday/1.6.1/css/pikaday.min.css">
<style>
.error-container { display: none; margin-bottom: 16px; padding: 5px 10px; text-align: center; color: #fff; }
.is-loading { animation: blink .5s infinite; }
@keyframes blink { 0% { opacity: 1; } 50% { opacity: 0; } 100% { opacity: 1; } }

// some overwrites google-styles vs. pikaday styles
.pika-lendar { margin: 4px; }
.pika-label {font-size: 12px; }
.pika-table th { font-size: 10px; }
button.pika-button, button.pika-prev, button.pika-next { min-width: initial; height: auto; border: 0;}
button.pika-button {font-size: 10px; line-height: 12px; padding: 4px 3px; }
.is-rtl button.pika-next, button.pika-prev { background: none no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAUklEQVR42u3VMQoAIBADQf8Pgj+OD9hG2CtONJB2ymQkKe0HbwAP0xucDiQWARITIDEBEnMgMQ8S8+AqBIl6kKgHiXqQqAeJepBo/z38J/U0uAHlaBkBl9I4GwAAAABJRU5ErkJggg==); border: 0; }
.is-rtl button.pika-prev, button.pika-next { background: none no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAAU0lEQVR42u3VOwoAMAgE0dwfAnNjU26bYkBCFGwfiL9VVWoO+BJ4Gf3gtsEKKoFBNTCoCAYVwaAiGNQGMUHMkjGbgjk2mIONuXo0nC8XnCf1JXgArVIZAQh5TKYAAAAASUVORK5CYII=); border: 0; }
</style>
</head>
<body>
<div id="response-message" class="error-container" role="dialog"></div>

<form name="worklog" action="" method="post">
<fieldset class="block">
<legend>Select User</legend>

<div class="block">
<!--<label for="wlUser">Select user</label>-->
<select name="wlUser" id="wlUser" class="block is-loading">
<option value=""></option>
</select>
</div>

<!-- Groups not supported yet
<div class="block">OR</div>
<div class"block">
<label for="wlGroup">Select Group</label>
<select name="wlGroup" id="wlGroup" class="block is-loading">
<option value=""></option>
</select>
</div>
-->
</fieldset>

<fieldset class="block">
<legend>Options</legend>

<? var now = (new Date()).getTime(), MilliPerDay = 1000 * 60 * 60 * 24; ?>
<div class="block">
<div class="inline" style="vertical-align:top;">
<label for="wlStartDate">Start Date:</label><!-- default to now()-7 days -->
<input type="text" name="wlStartDate" class="block" style="width:80%" value="<?= Utilities.formatDate(new Date(now - 7 * MilliPerDay), 'Etc/GMT', 'yyyy-MM-dd') ?>" />
</div>
<div class="inline" style="vertical-align:top;">
<label for="wlEndDate">End Date:</label><!-- default to now() -->
<input type="text" name="wlEndDate" class="block" style="width:80%" value="<?= Utilities.formatDate(new Date(now), 'Etc/GMT', 'yyyy-MM-dd') ?>" />
</div>
</div>

<div class="block">
<label for="wlTimeFormat" class="block">Reporting Time Format:</label>
<input type="radio" id="wlTimeFormatOne" name="wlTimeFormat" value="1" checked /> <label for="wlTimeFormatOne" title="human readable">1d 7h 59m</label><br/>
<input type="radio" id="wlTimeFormatTwo" name="wlTimeFormat" value="2" /> <label for="wlTimeFormatTwo" title="workhours as float, good for post calculations">7.5</label>
</div>
</fieldset>

<div class="block">
<button type="submit" class="action">View Report</button>
<button type="button" onclick="google.script.host.close()">Cancel</button>
</div>
</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/pikaday/1.6.1/pikaday.min.js"></script>
<script>
var frmWorklog = document.forms['worklog'];
var valid = false;
var timeout = null;
var alert = document.getElementById('response-message');
var action = frmWorklog.querySelector('[type=submit]');

function onInitWorklog(response) {
/* DEV */

// gen user dropdown
var sel = document.getElementById('wlUser');
var fragment = document.createDocumentFragment();
response.users.forEach(function(user, index) {
var opt = document.createElement('option');
opt.innerHTML = user.displayName;
opt.value = user.name;
fragment.appendChild(opt);
});
sel.appendChild(fragment);
sel.className = 'block';

// gen group dropdown
sel = document.getElementById('wlGroup');
fragment = document.createDocumentFragment();
response.groups.forEach(function(group, index) {
var opt = document.createElement('option');
opt.innerHTML = group.name; //group.displayName;
opt.value = group.name;
fragment.appendChild(opt);
});
sel.appendChild(fragment);
sel.className = 'block';
}

function formSubmitHandler(event) {
if (event) event.preventDefault();

//hideAlert();
//if (!valid) return;
//showAlert('fetch data ...', 1);
var formData = {
wlAuthorU: frmWorklog.wlUser.value,
//wlAuthorG: frmWorklog.wlGroup.value,
wlAuthorName: frmWorklog.wlUser.options[frmWorklog.wlUser.selectedIndex].text,
wlStartDate: frmWorklog.wlStartDate.value,
wlEndDate: frmWorklog.wlEndDate.value,
wlTimeFormat: frmWorklog.querySelector('input[name="wlTimeFormat"]:checked').value
};

google.script.run
//.withSuccessHandler(onResponse)
//.withFailureHandler(onResponse)
.createWorklog(formData);

// dont wait for response - bubble up all states not possible
// instead,show loading animation for 2sec and then close dialog
// success/error feedback handled inside sheet.
google.script.host.close();
}

google.script.run
.withSuccessHandler(onInitWorklog)
.fetchUsersAndGroups(true);

frmWorklog.addEventListener('submit', formSubmitHandler);
//input.forEach(function(el){ el.addEventListener('change', inputValidatyHandler); });
//window.addEventListener('load', );

var pickerFrom = new Pikaday({
field: frmWorklog.wlStartDate,
format: 'yyyy-MM-dd',
maxDate: new Date(),
onSelect: function() {
if (this.getDate() > pickerTo.getDate()) {
pickerTo.setDate(this.getDate());
}
},
toString(date) {
return date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + ('0' + date.getDate()).slice(-2);
}
});
var pickerTo = new Pikaday({
field: frmWorklog.wlEndDate,
format: 'yyyy-MM-dd',
maxDate: new Date(),
onSelect: function() {
if (this.getDate() < pickerFrom.getDate()) {
pickerFrom.setDate(this.getDate());
}
},
toString(date) {
return date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + ('0' + date.getDate()).slice(-2);
}
});
</script>
</body>
</html>
Loading

0 comments on commit d432690

Please sign in to comment.