newest version of timetracker
This commit is contained in:
@@ -14,11 +14,13 @@ import { getRepos, getYears, getQuarters, getIssues, type QuarterData, type Issu
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { i18n } from '@/plugins/02_i18n'
|
||||
import type { TableColumn } from '@nuxt/ui'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
|
||||
|
||||
const authStore = useAuthStore()
|
||||
|
||||
const { t } = useI18n()
|
||||
const repos = ref<number[]>([])
|
||||
const years = ref<number[]>([])
|
||||
const quarters = ref<QuarterData[]>([])
|
||||
@@ -47,7 +49,7 @@ async function loadData<T>(fetchFn: () => Promise<any>, target: Ref<T[]>, errorM
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadData(() => getRepos(), repos, i18n.t('repo_chart.failed_to_load_repositories')))
|
||||
onMounted(() => loadData(() => getRepos(), repos, t('repo_chart.failed_to_load_repositories')))
|
||||
|
||||
watch(selectedRepo, async (newRepo) => {
|
||||
selectedYear.value = null
|
||||
@@ -55,7 +57,7 @@ watch(selectedRepo, async (newRepo) => {
|
||||
quarters.value = []
|
||||
issues.value = []
|
||||
if (newRepo) {
|
||||
await loadData(() => getYears(newRepo), years, i18n.t('repo_chart.failed_to_load_years'))
|
||||
await loadData(() => getYears(newRepo), years, t('repo_chart.failed_to_load_years'))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -63,7 +65,7 @@ watch(selectedYear, async (newYear) => {
|
||||
selectedQuarter.value = null
|
||||
issues.value = []
|
||||
if (newYear && selectedRepo.value) {
|
||||
await loadData(() => getQuarters(selectedRepo.value!, newYear), quarters, i18n.t('repo_chart.failed_to_load_quarters'))
|
||||
await loadData(() => getQuarters(selectedRepo.value!, newYear), quarters, t('repo_chart.failed_to_load_quarters'))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -91,7 +93,7 @@ async function loadIssues(repoID: number, year: number, quarterStr: string) {
|
||||
issues.value = response.items || []
|
||||
totalItems.value = response.items_count || 0
|
||||
} catch (e: any) {
|
||||
error.value = e?.message || i18n.t('repo_chart.failed_to_load_issues')
|
||||
error.value = e?.message || t('repo_chart.failed_to_load_issues')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -101,24 +103,36 @@ const chartData = computed(() => ({
|
||||
labels: quarters.value.map((q) => q.quarter),
|
||||
datasets: [
|
||||
{
|
||||
label: i18n.t('repo_chart.hours_worked'),
|
||||
label: t('repo_chart.hours_worked'),
|
||||
backgroundColor: '#3b82f6',
|
||||
data: quarters.value.map((q) => q.time),
|
||||
},
|
||||
],
|
||||
}))
|
||||
|
||||
const chartOptions = {
|
||||
const chartOptions = computed(() => ({
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
onClick: (_event: any, elements: any[]) => {
|
||||
if (elements.length > 0) {
|
||||
const index = elements[0].index
|
||||
const quarter = quarters.value[index]
|
||||
if (quarter) {
|
||||
selectedQuarter.value = quarter.quarter
|
||||
}
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: { position: 'top' as const },
|
||||
title: { display: true, text: i18n.t('repo_chart.work_by_quarter') },
|
||||
title: { display: true, text: t('repo_chart.work_by_quarter') },
|
||||
},
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: i18n.t('repo_chart.hours') } },
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: { display: true, text: t('repo_chart.hours') },
|
||||
},
|
||||
},
|
||||
}
|
||||
}))
|
||||
|
||||
const hasData = computed(() => quarters.value.length > 0)
|
||||
const hasIssues = computed(() => issues.value.length > 0)
|
||||
@@ -126,31 +140,27 @@ const hasIssues = computed(() => issues.value.length > 0)
|
||||
const items = computed(() => repos.value.map(r => ({ value: r, label: `Repo ${r}` })))
|
||||
|
||||
const yearItems = computed(() => [
|
||||
{ value: null, label: i18n.t('repo_chart.select_a_year') },
|
||||
{ value: null, label: t('repo_chart.select_a_year') },
|
||||
...years.value.map(y => ({ value: y, label: String(y) }))
|
||||
])
|
||||
|
||||
const quarterItems = computed(() => [
|
||||
{ value: null, label: i18n.t('repo_chart.all_quarters') },
|
||||
{ value: null, label: t('repo_chart.all_quarters') },
|
||||
...quarters.value.map(q => ({
|
||||
value: q.quarter,
|
||||
label: `${q.quarter} (${q.time.toFixed(1)}h)`
|
||||
}))
|
||||
])
|
||||
|
||||
const columns: TableColumn<IssueTimeSummary>[] = [
|
||||
const columns = computed<TableColumn<IssueTimeSummary>[]>(() => [
|
||||
{
|
||||
accessorKey: 'IssueID',
|
||||
header: 'ID',
|
||||
header: 'ID'
|
||||
},
|
||||
{
|
||||
accessorKey: 'IssueName',
|
||||
header: i18n.t('repo_chart.issue_name'),
|
||||
},
|
||||
// {
|
||||
// accessorKey: 'Initials',
|
||||
// header: i18n.t('repo_chart.user_initials'),
|
||||
// },
|
||||
{
|
||||
accessorKey: 'CreatedDate',
|
||||
header: i18n.t('repo_chart.created_on'),
|
||||
@@ -159,29 +169,15 @@ const columns: TableColumn<IssueTimeSummary>[] = [
|
||||
return date.toLocaleDateString(i18n.locale.value)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: 'CreatedDate',
|
||||
header: i18n.t('repo_chart.created_on'),
|
||||
cell: ({ row }) => {
|
||||
const date = new Date(row.getValue('CreatedDate'))
|
||||
return date.toLocaleTimeString(i18n.locale.value)
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: 'TotalHoursSpent',
|
||||
header: i18n.t('repo_chart.hours_spent'),
|
||||
meta: {
|
||||
class: {
|
||||
th: 'text-right',
|
||||
td: 'text-right font-medium'
|
||||
}
|
||||
class: { th: 'text-right', td: 'text-right font-medium' }
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const hours = row.getValue('TotalHoursSpent')
|
||||
return `${hours}h`
|
||||
}
|
||||
cell: ({ row }) => `${row.getValue('TotalHoursSpent')}h`
|
||||
},
|
||||
]
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -211,14 +207,16 @@ const columns: TableColumn<IssueTimeSummary>[] = [
|
||||
}}</label>
|
||||
<USelect v-model="selectedYear" :items="yearItems"
|
||||
:disabled="loading || !selectedRepo || years.length === 0"
|
||||
:placeholder="$t('repo_chart.select_a_year')" class="dark:text-white text-black placeholder:text-(--placeholder)" />
|
||||
:placeholder="$t('repo_chart.select_a_year')"
|
||||
class="dark:text-white text-black placeholder:text-(--placeholder)" />
|
||||
</div>
|
||||
<div class="flex flex-col min-w-[192px]">
|
||||
<label class="mb-1 text-sm font-medium text-black dark:text-white">{{ $t('repo_chart.quarter')
|
||||
}}</label>
|
||||
<USelect v-model="selectedQuarter" :items="quarterItems"
|
||||
:disabled="loading || !selectedYear || quarters.length === 0"
|
||||
:placeholder="$t('repo_chart.all_quarters')" class="dark:text-white text-black placeholder:text-(--placeholder)" />
|
||||
:placeholder="$t('repo_chart.all_quarters')"
|
||||
class="dark:text-white text-black placeholder:text-(--placeholder)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user