From 991286c124eaece8c15659009712c32a0553f9b1 Mon Sep 17 00:00:00 2001 From: Paul Pestov <10750176+paulpestov@users.noreply.github.com> Date: Tue, 5 Dec 2023 19:47:08 +0100 Subject: [PATCH] feat: display release info in timeline charts --- src/components/Workflows.vue | 12 +++- .../workflows/timeline/BaseTimelineChart.vue | 25 +++++++++ .../timeline/BaseTimelineDetailedChart.vue | 56 +++++++++++++++++-- src/helpers/metric-chart-tooltip-content.ts | 3 +- src/store/workflows-store.ts | 4 +- src/types/index.d.ts | 11 ++-- 6 files changed, 97 insertions(+), 14 deletions(-) diff --git a/src/components/Workflows.vue b/src/components/Workflows.vue index d14bb8e..151c568 100644 --- a/src/components/Workflows.vue +++ b/src/components/Workflows.vue @@ -1,4 +1,4 @@ -<script setup> +<script setup lang="ts"> import { onMounted, ref, watch } from "vue" import api from '@/helpers/api' import { useRouter, useRoute } from "vue-router" @@ -10,6 +10,7 @@ import WorkflowsTimeline from "@/components/workflows/WorkflowsTimeline.vue" import filtersStore from "@/store/filters-store" import workflowsStore from "@/store/workflows-store" + import type { ReleaseInfo } from "@/types"; const { t } = useI18n() @@ -51,9 +52,16 @@ workflowsStore.gt = await api.getGroundTruth() workflowsStore.workflows = await api.getWorkflows() - loading.value = false + const releasesObj = workflowsStore.runs.reduce((acc, cur) => { + acc[cur.metadata.release_info.tag_name] = cur.metadata.release_info + return acc + }, {}) + + workflowsStore.releases = Object.keys(releasesObj).map(key => <ReleaseInfo>releasesObj[key]) setEvalColors(workflowsStore.runs) + + loading.value = false }) </script> <template> diff --git a/src/components/workflows/timeline/BaseTimelineChart.vue b/src/components/workflows/timeline/BaseTimelineChart.vue index 34b3d3c..8c92c69 100644 --- a/src/components/workflows/timeline/BaseTimelineChart.vue +++ b/src/components/workflows/timeline/BaseTimelineChart.vue @@ -4,6 +4,7 @@ import { ref, watch, computed, onMounted } from "vue" import type { TimelineChartDataPoint } from "@/types" import { createTooltip, setEventListeners } from "@/helpers/d3/d3-tooltip" import colors from 'tailwindcss/colors' +import workflowsStore from "@/store/workflows-store" interface Props { @@ -41,6 +42,10 @@ function isUp(data: TimelineChartDataPoint[], higherIsUp = true) { else return -1 } +function renderReleases() { + +} + function render([data, startDate, endDate, maxY]) { if (!data || !startDate || !endDate) return @@ -129,6 +134,21 @@ function render([data, startDate, endDate, maxY]) { setEventListeners(svg.selectAll('.chart-point'), tooltip, { useData: props.tooltipContent }) + + const releasesGroup = svg + .append('g') + .classed('releases-group', true) + + workflowsStore.releases.forEach(release => { + const xPos = x(new Date(release.published_at)) + + releasesGroup + .append("path") + .attr("stroke-width", 1.5) + .attr('stroke-dasharray', 4) + .attr("d", d3.line()([[xPos, y(0)], [xPos, y(maxY)]])) + }) + // Append the SVG element. container.value.append(svg.node()) } @@ -146,6 +166,11 @@ watch([() => props.data, () => props.startDate, () => props.endDate, () => props <style lang="scss"> +.releases-group { + fill: none; + stroke: theme('colors.gray.400'); +} + .path-group { path { fill: none; diff --git a/src/components/workflows/timeline/BaseTimelineDetailedChart.vue b/src/components/workflows/timeline/BaseTimelineDetailedChart.vue index 889e732..e9abdbb 100644 --- a/src/components/workflows/timeline/BaseTimelineDetailedChart.vue +++ b/src/components/workflows/timeline/BaseTimelineDetailedChart.vue @@ -4,6 +4,7 @@ import { ref, watch, computed, onMounted } from "vue" import type { TimelineChartDataPoint } from "@/types" import { createTooltip, setEventListeners } from "@/helpers/d3/d3-tooltip" import colors from 'tailwindcss/colors' +import workflowsStore from "@/store/workflows-store" interface Props { @@ -43,7 +44,7 @@ function isUp(data: TimelineChartDataPoint[], higherIsUp = true) { else return -1 } -function render([data, startDate, endDate]) { +function render([data, startDate, endDate, maxY]) { if (!data || !startDate || !endDate) return if (data.length === 0) return @@ -55,7 +56,7 @@ function render([data, startDate, endDate]) { // Declare the y (vertical position) scale. const y = d3.scaleLinear() - .domain([0, _maxY.value]) + .domain([0, maxY]) .range([height - marginBottom, marginTop]) // Create the SVG container. @@ -136,6 +137,48 @@ function render([data, startDate, endDate]) { setEventListeners(svg.selectAll('.chart-point'), tooltip, { useData: props.tooltipContent }) + const releasesGroup = svg + .append('g') + .classed('releases-group', true) + + workflowsStore.releases.forEach(release => { + const xPos = x(new Date(release.published_at)) + + const releaseGroup = releasesGroup.append('g') + + releaseGroup + .append("path") + .attr("stroke-width", 1.5) + .attr('stroke-dasharray', 4) + .attr("d", d3.line()([[xPos, y(0)], [xPos, y(maxY)]])) + + const group = releaseGroup.append('g') + + group + .append('rect') + .attr("x", xPos) + .attr("y", y(maxY)) + .attr('width', 80) + .attr('height', 18) + .style("fill", 'white') + + group + .append("text") + .classed('tag-name', true) + .attr("y", y(maxY)) + .attr("x", xPos) + .attr('dy', 12) + .attr('dx', 5) + .text(release.tag_name) + .attr('stroke', 'none') + .attr('fill', colors.gray['600']) + .style('cursor', 'pointer') + + releaseGroup.on('mouseenter', function(e) { + this.parentElement.appendChild(this) + }) + }) + // Append the SVG element. if (!container.value) return container.value.replaceChildren() @@ -143,10 +186,10 @@ function render([data, startDate, endDate]) { } onMounted(() => { - render([props.data, props.startDate, props.endDate]) + render([props.data, props.startDate, props.endDate, props.maxY]) }) -watch([() => props.data, () => props.startDate, () => props.endDate], render) +watch([() => props.data, () => props.startDate, () => props.endDate, () => props.maxY], render) </script> @@ -157,6 +200,11 @@ watch([() => props.data, () => props.startDate, () => props.endDate], render) <style lang="scss"> +.releases-group { + .tag-name { + font-size: 10px; + } +} .path-group { path { diff --git a/src/helpers/metric-chart-tooltip-content.ts b/src/helpers/metric-chart-tooltip-content.ts index 5c8193e..82caaad 100644 --- a/src/helpers/metric-chart-tooltip-content.ts +++ b/src/helpers/metric-chart-tooltip-content.ts @@ -1,13 +1,12 @@ import type { EvaluationResultsDocumentWide, TimelineChartDataPoint } from "@/types" import { createReadableMetricValue } from "@/helpers/utils" -import { useI18n } from "vue-i18n" import i18n from '@/i18n' const { t } = i18n.global function metricChartTooltipContent(d: TimelineChartDataPoint, metric: string) { return ` <div class=""> - <span class="font-semibold">${t('date')}:</span> <span>${d.date.getDate()}.${d.date.getMonth()}.${d.date.getFullYear()}</span> + <span class="font-semibold">${t('date')}:</span> <span>${d.date.getDate()}.${d.date.getMonth() + 1}.${d.date.getFullYear()}</span> </div> <div class=""> <span class="font-semibold">${t(metric)}:</span> <span>${createReadableMetricValue(<keyof EvaluationResultsDocumentWide>metric, d.value)}</span> diff --git a/src/store/workflows-store.ts b/src/store/workflows-store.ts index ccd9059..c443700 100644 --- a/src/store/workflows-store.ts +++ b/src/store/workflows-store.ts @@ -1,5 +1,5 @@ import { reactive } from "vue" -import type { EvaluationRun, GroundTruth, Workflow } from "@/types" +import type { EvaluationRun, GroundTruth, ReleaseInfo, Workflow } from "@/types" import { mapGtId } from "@/helpers/utils" function normalizeDate(dateString: string): string { @@ -10,6 +10,7 @@ export default reactive<{ gt: GroundTruth[], workflows: Workflow[], runs: EvaluationRun[], + releases: ReleaseInfo[], getRuns: (gtId: string, workflowId?: string) => EvaluationRun[] getLatestRuns: () => EvaluationRun[], getGtById: (id: string) => GroundTruth | null @@ -18,6 +19,7 @@ export default reactive<{ gt: [], workflows: [], runs: [], + releases: [], getRuns(gtId: string, workflowId?: string) { return this.runs .filter( diff --git a/src/types/index.d.ts b/src/types/index.d.ts index fb682d3..02c7f3b 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -15,11 +15,6 @@ export interface Workspace { label: string } -export interface ReleaseInfo { - id: string, - tage_name: string -} - export interface WorkflowStep { id: string, params: WorkflowStepParams @@ -88,3 +83,9 @@ export interface FilterOption { label: string } +export interface ReleaseInfo { + id: number, + published_at: string, + tag_name: string +} + -- GitLab