From b1955363a66a095c62f09a3057ad663925c6ec65 Mon Sep 17 00:00:00 2001 From: "Calum H." Date: Wed, 29 Jan 2025 02:34:28 +0000 Subject: [PATCH] refactor(knossos): Rewrite date range system on analytics dashboard. (#1301) * Start work on refactoring date range system. * Use timeResolution terminology. * "Last month" initial default. * Migrate fully to dayjs - ease of use. * Discard changes to pnpm-lock.yaml * utilize getter * Fix date label in ChartDisplay.vue * Finish cleanup * Update STAGING_API_URL in nuxt.config.ts * Lint fixes * Refactor ChartDisplay.vue to handle loading state in selectedRange and formattedCategorySubtitle * Remove modal impl --------- Signed-off-by: Calum H. Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com> --- .../src/components/ui/charts/ChartDisplay.vue | 290 +++++++++++++++--- apps/frontend/src/plugins/dayjs.js | 3 + apps/frontend/src/utils/analytics.js | 14 +- 3 files changed, 256 insertions(+), 51 deletions(-) diff --git a/apps/frontend/src/components/ui/charts/ChartDisplay.vue b/apps/frontend/src/components/ui/charts/ChartDisplay.vue index f60edd474..f57a92f4d 100644 --- a/apps/frontend/src/components/ui/charts/ChartDisplay.vue +++ b/apps/frontend/src/components/ui/charts/ChartDisplay.vue @@ -14,7 +14,7 @@ {{ formatCategoryHeader(selectedChart) }} + + {{ formattedCategorySubtitle }} +
@@ -322,7 +326,7 @@ const props = withDefaults( * @deprecated Use `ranges` instead */ resoloutions?: Record; - ranges?: Record; + ranges?: RangeObject[]; personal?: boolean; }>(), { @@ -335,12 +339,6 @@ const props = withDefaults( const projects = ref(props.projects || []); -const selectableRanges = Object.entries(props.ranges).map(([duration, extra]) => ({ - label: typeof extra === "string" ? extra : extra[0], - value: Number(duration), - res: typeof extra === "string" ? Number(duration) : extra[1], -})); - // const selectedChart = ref('downloads') const selectedChart = computed({ get: () => { @@ -413,33 +411,78 @@ const isUsingProjectColors = computed({ }, }); +const startDate = ref(dayjs().startOf("day")); +const endDate = ref(dayjs().endOf("day")); +const timeResolution = ref(30); + +onBeforeMount(() => { + // Load cached data and range from localStorage - cache. + if (import.meta.client) { + const rangeLabel = localStorage.getItem("analyticsSelectedRange"); + if (rangeLabel) { + const range = props.ranges.find((r) => r.getLabel([dayjs(), dayjs()]) === rangeLabel)!; + + if (range !== undefined) { + internalRange.value = range; + const ranges = range.getDates(dayjs()); + timeResolution.value = range.timeResolution; + startDate.value = ranges.startDate; + endDate.value = ranges.endDate; + } + } + } +}); + +onMounted(() => { + if (internalRange.value === null) { + internalRange.value = props.ranges.find( + (r) => r.getLabel([dayjs(), dayjs()]) === "Previous 30 days", + )!; + } + + const ranges = selectedRange.value.getDates(dayjs()); + startDate.value = ranges.startDate; + endDate.value = ranges.endDate; + timeResolution.value = selectedRange.value.timeResolution; +}); + +const internalRange: Ref = ref(null as unknown as RangeObject); + +const selectedRange = computed({ + get: () => { + return internalRange.value; + }, + set: (newRange) => { + const ranges = newRange.getDates(dayjs()); + startDate.value = ranges.startDate; + endDate.value = ranges.endDate; + timeResolution.value = newRange.timeResolution; + + internalRange.value = newRange; + + if (import.meta.client) { + localStorage.setItem( + "analyticsSelectedRange", + internalRange.value?.getLabel([dayjs(), dayjs()]) ?? "Previous 30 days", + ); + } + }, +}); + const analytics = useFetchAllAnalytics( resetCharts, projects, selectedDisplayProjects, props.personal, + startDate, + endDate, + timeResolution, ); -const { startDate, endDate, timeRange, timeResolution } = analytics; - -const selectedRange = computed({ - get: () => { - return ( - selectableRanges.find((option) => option.value === timeRange.value) || { - label: "Custom", - value: timeRange.value, - } - ); - }, - set: (newRange: { label: string; value: number; res?: number }) => { - timeRange.value = newRange.value; - startDate.value = Date.now() - timeRange.value * 60 * 1000; - endDate.value = Date.now(); - - if (newRange?.res) { - timeResolution.value = newRange.res; - } - }, +const formattedCategorySubtitle = computed(() => { + return ( + selectedRange.value?.getLabel([dayjs(startDate.value), dayjs(endDate.value)]) ?? "Loading..." + ); }); const selectedDataSet = computed(() => { @@ -484,6 +527,9 @@ const onToggleColors = () => {