Time tracking you can host anywhere, built on Django. Full export support in multiple formats and easily extensible.
djangodockerhandcodedpythonself-hostedtime-trackingtimetracker
1<template>
2<card
3 :index="index"
4 :delete_perm="$perms.delete_project"
5 :change_perm="$perms.change_project"
6 :add_perm="$perms.add_project"
7 @edit="$emit('modal')"
8 @detail="showEntries"
9 @delete="deleteProject(project)">
10 <template slot="card-body">
11 <div class="d-flex flex-column h-100">
12 <div class="card-title h5 font-weight-bold">
13 {{ project.name }}
14 </div>
15 <div v-if="project.client" class="card-subtitle h6 text-muted mb-4">
16 for <strong>{{ getClient(project.client).name }}</strong>
17 </div>
18 <div v-if="project.total_duration && project.total_entries" class="card-subtitle h6 mb-5 flex-grow-1">
19 <icon :icon="['fas', 'list']" class="mr-1 text-muted"/>
20 {{ project.total_entries }}
21 <icon :icon="['fas', 'clock']" class="ml-3 mr-1 text-muted"/>
22 {{ project.total_duration }}
23 </div>
24 <div v-if="project.percent_done" class="card-subtitle h6 w-100">
25 <div class="progress w-100">
26 <div
27 :class="['progress-bar', [project.percent_done > 100 ? 'bg-danger' : '']]"
28 :style="{ width: project.percent_done + '%' }">
29 {{ project.percent_done }}%
30 </div>
31 </div>
32 </div>
33 </div>
34 </template>
35</card>
36</template>
37
38
39<script>
40 import {mapActions, mapGetters} from 'vuex';
41
42import Card from '../cards/card.vue';
43
44
45export default {
46 components: {
47 Card,
48 },
49 props: {
50 project: {
51 type: Object,
52 default: () => {
53 return {
54 id: null,
55 }
56 },
57 },
58 index: {
59 type: Number,
60 default: null,
61 },
62 },
63 computed: {
64 ...mapGetters({
65 getClient: 'clients/getClient',
66 }),
67 },
68 methods: {
69 ...mapActions({
70 deleteProject: 'projects/deleteProject',
71 }),
72
73 showEntries(){
74 if(!this.project.id){
75 this.$emit('modal');
76 return;
77 }
78 this.$store.commit("reports/reset");
79 this.$store.commit("reports/setProject", this.project.url);
80 this.$router.push("/reports");
81 }
82 },
83};
84</script>