Compare commits

...
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

9 Commits

  1. 4
      .idea/timetrack.iml
  2. BIN
      assets/img/gitlab.png
  3. BIN
      assets/img/jira.png
  4. BIN
      assets/img/redmine.png
  5. 4
      css/app.css
  6. 39
      index.html
  7. 66
      js/app.js

4
.idea/timetrack.iml

@ -4,5 +4,9 @@
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="izitoast" level="application" />
<orderEntry type="library" name="quill" level="application" />
<orderEntry type="library" name="quill.snow" level="application" />
<orderEntry type="library" name="quill.bubble" level="application" />
</component> </component>
</module> </module>

BIN
assets/img/gitlab.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
assets/img/jira.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
assets/img/redmine.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

4
css/app.css

@ -234,3 +234,7 @@ nav, .card {
#trackerTasksModal input[type=range] { #trackerTasksModal input[type=range] {
width: 100%; width: 100%;
} }
.ticket-icon {
max-width: 24px;
}

39
index.html

@ -356,7 +356,10 @@
<div class="row"> <div class="row">
<template v-for="(ticket, ticketIndex) in tickets"> <template v-for="(ticket, ticketIndex) in tickets">
<div class="col-md-6"> <div class="col-md-6">
<h6><span v-if="isTicketNumber(ticket.number)"></span>{{ ticket.number }}</h6> <!-- <h6><span v-if="isTicketNumber(ticket.number)"></span>{{ ticket.number }}</h6>-->
<div class="form-group">
<input type="text" class="form-control" v-model="ticket.number" @keydown="updateStorage()" placeholder="Name">
</div>
<div class="form-group"> <div class="form-group">
<input type="text" class="form-control" v-model="ticket.description" @keydown="updateStorage()" placeholder="Beschreibung"> <input type="text" class="form-control" v-model="ticket.description" @keydown="updateStorage()" placeholder="Beschreibung">
@ -378,12 +381,24 @@
<i class="fas fa-archive"></i> <i class="fas fa-archive"></i>
</button> </button>
</div> </div>
<div class="col" v-if="ticket.tasks && ticket.tasks.length > 0">
<button class="btn btn-info ticket-action-button" data-bs-dismiss="modal"
@click="openTasksForTracker(ticket)" title="Tasks">
<i class="fas fa-clipboard-check"></i>
</button>
</div>
<div class="col" v-if="ticket.history.length > 0"> <div class="col" v-if="ticket.history.length > 0">
<button class="btn btn-info ticket-action-button" data-bs-dismiss="modal" <button class="btn btn-info ticket-action-button" data-bs-dismiss="modal"
@click="showHistoryForTracker(ticket)" title="History"> @click="showHistoryForTracker(ticket)" title="History">
<i class="fas fa-history"></i> <i class="fas fa-history"></i>
</button> </button>
</div> </div>
<div class="col" v-if="ticket.history.length > 0 && this.ticketSystemUrl">
<button class="btn btn-white ticket-action-button"
@click="sendLastBookingToTicketSystem(ticket)" title="Letzte Buchung in Ticketsystem eintragen">
<img :src="ticketSystemIcon" class="ticket-icon"/>
</button>
</div>
<div class="col"> <div class="col">
<button class="btn btn-danger ticket-action-button" <button class="btn btn-danger ticket-action-button"
@click="deleteTracker(ticketIndex)" title="Löschen"> @click="deleteTracker(ticketIndex)" title="Löschen">
@ -490,10 +505,14 @@
</div> </div>
<template v-for="(ticket, ticketIndex) in archive"> <template v-for="(ticket, ticketIndex) in archive">
<div class="col-md-6" v-if="searchQuery === '' || ticket.number.search(searchQuery) >= 0 || (ticket.description && ticket.description.search(searchQuery)) >= 0"> <div class="col-md-6" v-if="searchQuery === '' || ticket.number.search(searchQuery) >= 0 || (ticket.description && ticket.description.search(searchQuery)) >= 0">
<h6><span v-if="isTicketNumber(ticket.number)"></span>{{ ticket.number }}</h6> <div class="form-group">
<div v-if="ticket.description"> <input type="text" class="form-control" v-model="ticket.number" @keydown="updateStorage()" placeholder="Name">
<p class="fst-italic">{{ ticket.description }}</p> </div>
<div class="form-group">
<input type="text" class="form-control" v-model="ticket.description" @keydown="updateStorage()" placeholder="Beschreibung">
</div> </div>
<div class="ticket-time-info"> <div class="ticket-time-info">
<span class="float-end">{{ getTotalTime(ticket) }}</span> <span class="float-end">{{ getTotalTime(ticket) }}</span>
<span class="current-ticket-info">Gesamt: </span> <span class="current-ticket-info">Gesamt: </span>
@ -510,12 +529,24 @@
<i class="fas fa-power-off"></i> <i class="fas fa-power-off"></i>
</button> </button>
</div> </div>
<div class="col" v-if="ticket.tasks && ticket.tasks.length > 0">
<button class="btn btn-info ticket-action-button" data-bs-dismiss="modal"
@click="openTasksForTracker(ticket)" title="Tasks">
<i class="fas fa-clipboard-check"></i>
</button>
</div>
<div class="col" v-if="ticket.history.length > 0"> <div class="col" v-if="ticket.history.length > 0">
<button class="btn btn-info ticket-action-button" data-bs-dismiss="modal" <button class="btn btn-info ticket-action-button" data-bs-dismiss="modal"
@click="showHistoryForTracker(ticket)" title="History"> @click="showHistoryForTracker(ticket)" title="History">
<i class="fas fa-history"></i> <i class="fas fa-history"></i>
</button> </button>
</div> </div>
<div class="col" v-if="ticket.history.length > 0 && this.ticketSystemUrl">
<button class="btn btn-white ticket-action-button"
@click="sendLastBookingToTicketSystem(ticket)" title="Letzte Buchung in Ticketsystem eintragen">
<img :src="ticketSystemIcon" class="ticket-icon"/>
</button>
</div>
<div class="col"> <div class="col">
<button class="btn btn-danger ticket-action-button" <button class="btn btn-danger ticket-action-button"
@click="deleteTracker(ticketIndex, true)" title="Löschen"> @click="deleteTracker(ticketIndex, true)" title="Löschen">

66
js/app.js

@ -211,6 +211,7 @@ const TimeTrack = {
}, },
stopTracking(ticket) { stopTracking(ticket) {
// console.log(ticket); // console.log(ticket);
let component = this;
ticket.trackingStopped = moment(); ticket.trackingStopped = moment();
ticket.tracking = false; ticket.tracking = false;
@ -225,7 +226,6 @@ const TimeTrack = {
manually: false, manually: false,
minutes: Math.round(minutesSpent) minutes: Math.round(minutesSpent)
}; };
// console.log(historyEntry);
if (this.experimental.trackWorktime) { if (this.experimental.trackWorktime) {
if (ticket.paused) { if (ticket.paused) {
@ -233,6 +233,33 @@ const TimeTrack = {
} }
} }
if (this.ticketSystemUrl && this.isTicketNumber(ticket.number)) {
let finishedTasks = ticket.tasks.filter((task) => {
return task.finished > ticket.trackingStarted && task.finished < ticket.trackingStopped;
}).map((task) => {
return task.name;
});
iziToast.show({
message: 'Buchung gespeichert',
color: 'blue',
buttons: [
['<button><img src="'+component.ticketSystemIcon+'" class="ticket-icon"/></button>', function (instance, toast) {
instance.hide({
transitionOut: 'fadeOutUp',
onClosing: function () {
window.open(
component.ticketSystemUrl + ticket.number.replace('#', '').trim()+'/time_entries/new?time_entry[hours]='+(Math.round(minutesSpent)/60)+
'&time_entry[activity_id]=9&time_entry[comments]='+finishedTasks.join(', '),
'_blank'
);
}
}, toast, 'buttonName');
}, true]
]
});
}
ticket.history.pushToBeginning(historyEntry); ticket.history.pushToBeginning(historyEntry);
} }
@ -249,6 +276,28 @@ const TimeTrack = {
this.stopTracking(ticket); this.stopTracking(ticket);
}, },
sendLastBookingToTicketSystem(ticket) {
let component = this;
let latestHistoryItem = ticket.history[0];
if (this.ticketSystemUrl && this.isTicketNumber(ticket.number)) {
let finishedTasks = [];
if (ticket.tasks && ticket.tasks.length > 0) {
finishedTasks = ticket.tasks.filter((task) => {
return task.finished > latestHistoryItem.trackingStarted && task.finished < latestHistoryItem.trackingStopped;
}).map((task) => {
return task.name;
});
}
window.open(
component.ticketSystemUrl + ticket.number.replace('#', '').trim()+'/time_entries/new?time_entry[hours]='+(Math.round(latestHistoryItem.minutes)/60)+
'&time_entry[activity_id]=9&time_entry[comments]='+finishedTasks.join(', '),
'_blank'
);
}
},
resumeTracking(ticket) { resumeTracking(ticket) {
ticket.trackingStarted = moment(); ticket.trackingStarted = moment();
ticket.tracking = true; ticket.tracking = true;
@ -792,6 +841,21 @@ const TimeTrack = {
fun: this.fun, fun: this.fun,
theme: this.theme theme: this.theme
}); });
},
ticketSystemIcon() {
if (this.ticketSystemUrl) {
if (this.ticketSystemUrl.search('redmine')) {
return 'assets/img/redmine.png';
}
if (this.ticketSystemUrl.search('jira')) {
return 'assets/img/jira.png';
}
if (this.ticketSystemUrl.search('gitlab')) {
return 'assets/img/gitlab.png';
}
}
} }
} }
}; };