Skip to content

Commit 205fda3

Browse files
committed
Implement single shared data source for dashboard components
- Refactor Dashboard component to create shared data state (dashboardData) for consistent data across all dashboard views - Update TopSitesPieChart to accept shared data prop and use it when available - Update TabList component to accept shared data prop and prioritize shared data over independent fetching - Add watchers in both components to reactively update when shared data changes - Add loading state in Dashboard component while data is being fetched - Fix button text color to black for better visibility - Ensure pie chart, table, and legend all use the same single source of truth - Improve performance by loading data once instead of multiple times - Add proper null safety and default values to prevent TypeScript errors
1 parent 0da7ec0 commit 205fda3

File tree

7 files changed

+126
-53
lines changed

7 files changed

+126
-53
lines changed

dist/dark.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/dark.js

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/dashboard.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/src/dashboard.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/Dashboad.vue

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
@click="openChart(TypeOfChart.Blank)"
3131
>
3232
<span class="ml-5 blank-icon">🔒</span>
33-
{{ t('blank') }}
33+
{{ t('Blank') }}
3434
</button>
3535
</div>
3636
<HourlyChart v-if="chart == TypeOfChart.Horly" />
@@ -39,10 +39,13 @@
3939
<BlankView v-if="chart == TypeOfChart.Blank" />
4040
</div>
4141
<div v-if="chart == TypeOfChart.Horly">
42-
<TopSitesPieChart />
43-
<div class="tab-items">
44-
<TabList :type="TypeOfList.Dashboard" :showAllStats="false" />
45-
</div>
42+
<div v-if="isLoadingData" class="loading-indicator">Loading...</div>
43+
<template v-else>
44+
<TopSitesPieChart :tabListData="dashboardData" />
45+
<div class="tab-items">
46+
<TabList :type="TypeOfList.Dashboard" :showAllStats="false" :tabListData="dashboardData" />
47+
</div>
48+
</template>
4649
</div>
4750
</template>
4851

@@ -60,14 +63,21 @@ import NotesView from './NotesView.vue';
6063
import BlankView from './BlankView.vue';
6164
import TabList from '../components/TabList.vue';
6265
import TopSitesPieChart from './TopSitesPieChart.vue';
63-
import { TypeOfList } from '../utils/enums';
66+
import { TypeOfList, SortingBy } from '../utils/enums';
6467
import { onMounted, ref, onUnmounted, watch } from 'vue';
6568
import Browser from 'webextension-polyfill';
69+
import { useTodayTabListSummary } from '../functions/useTodayTabListSummary';
70+
import { TabListSummary } from '../dto/tabListSummary';
71+
import { Tab } from '../entity/tab';
6672
6773
const { t } = useI18n();
6874
const chart = ref<TypeOfChart>();
6975
const refreshTimer = ref<number | null>(null);
7076
77+
// Shared data state for dashboard components
78+
const dashboardData = ref<TabListSummary | null>(null);
79+
const isLoadingData = ref<boolean>(true);
80+
7181
enum TypeOfChart {
7282
Horly,
7383
Interval,
@@ -79,28 +89,23 @@ enum TypeOfChart {
7989
const CHART_PREFERENCE_KEY = 'dashboard_chart_preference';
8090
8191
onMounted(async () => {
82-
// Get saved preference from storage
8392
try {
84-
const result = await Browser.storage.local.get(CHART_PREFERENCE_KEY);
85-
const savedPreference = result[CHART_PREFERENCE_KEY];
86-
87-
// If we have a saved preference, use it
88-
if (savedPreference !== undefined) {
89-
chart.value = savedPreference;
93+
const result = await Browser.storage.local.get([CHART_PREFERENCE_KEY]);
94+
if (result[CHART_PREFERENCE_KEY] !== undefined) {
95+
chart.value = result[CHART_PREFERENCE_KEY];
9096
} else {
91-
// Default to hourly view
9297
chart.value = TypeOfChart.Horly;
9398
}
9499
95-
// Start refresh timer if hourly view is active
100+
// Load dashboard data on mount
101+
await loadDashboardData();
102+
96103
if (chart.value === TypeOfChart.Horly) {
97104
startRefreshTimer();
98105
}
99106
} catch (error) {
100107
console.error('Error loading chart preference:', error);
101-
// Default to hourly view if error
102108
chart.value = TypeOfChart.Horly;
103-
startRefreshTimer();
104109
}
105110
});
106111
@@ -112,8 +117,23 @@ onUnmounted(() => {
112117
// Create a simple event bus for component communication
113118
const refreshEvent = new CustomEvent('refresh-data');
114119
115-
// Function to emit the refresh event to child components
116-
function emitRefreshEvent() {
120+
// Function to load dashboard data
121+
async function loadDashboardData() {
122+
isLoadingData.value = true;
123+
try {
124+
// Load data using the same function that TabList and TopSitesPieChart use
125+
const data = await useTodayTabListSummary(SortingBy.UsageTime);
126+
dashboardData.value = data;
127+
} catch (error) {
128+
console.error('Error loading dashboard data:', error);
129+
} finally {
130+
isLoadingData.value = false;
131+
}
132+
}
133+
134+
// Function to emit the refresh event to child components and reload data
135+
async function emitRefreshEvent() {
136+
await loadDashboardData();
117137
window.dispatchEvent(refreshEvent);
118138
}
119139
@@ -177,7 +197,7 @@ async function openChart(type: TypeOfChart) {
177197
/* .chartByHours height removed */
178198
.chart-btn {
179199
background-color: rgb(192, 192, 192);
180-
color: #fff;
200+
color: #000;
181201
border-radius: 7px;
182202
height: 36px;
183203
line-height: 35px;
@@ -193,6 +213,12 @@ async function openChart(type: TypeOfChart) {
193213
194214
.chart-btn.active {
195215
background-color: #5377af !important;
196-
color: white;
216+
color: #000;
217+
}
218+
219+
.loading-indicator {
220+
text-align: center;
221+
padding: 20px;
222+
font-size: 16px;
197223
}
198224
</style>

src/components/TabList.vue

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,37 @@ export default {
4444
</script>
4545

4646
<script lang="ts" setup>
47-
import { computed, onMounted, onUnmounted, ref } from 'vue';
47+
import { computed, onMounted, onUnmounted, ref, PropType, watch } from 'vue';
4848
import { useI18n } from 'vue-i18n';
4949
import TabItem from '../components/TabItem.vue';
5050
import TabItemHeader from '../components/TabItemHeader.vue';
5151
import DonutChart from '../components/DonutChart.vue';
5252
import OverallStatistics from '../components/OverallStatistics.vue';
5353
import { Tab } from '../entity/tab';
5454
import { SortingBy, TypeOfList } from '../utils/enums';
55+
import { CurrentTabItem } from '../dto/currentTabItem';
5556
import { useTodayTabListSummary } from '../functions/useTodayTabListSummary';
5657
import { useAllTabListSummary } from '../functions/useAllTabListSummary';
57-
import { CurrentTabItem } from '../dto/currentTabItem';
5858
import { todayLocalDate } from '../utils/date';
5959
import { OverallStats } from '../dto/tabListSummary';
60+
import { TabListSummary } from '../dto/tabListSummary';
6061
6162
const { t } = useI18n();
6263
63-
const props = defineProps<{
64-
type: TypeOfList;
65-
showAllStats: boolean;
66-
}>();
64+
const props = defineProps({
65+
type: {
66+
type: Number as PropType<TypeOfList>,
67+
required: true,
68+
},
69+
showAllStats: {
70+
type: Boolean,
71+
default: true,
72+
},
73+
tabListData: {
74+
type: Object as PropType<TabListSummary | null>,
75+
default: null
76+
}
77+
});
6778
6879
const isShowOverallStats = computed(() => props.showAllStats && props.type == TypeOfList.All);
6980
@@ -90,25 +101,38 @@ function showAllWebSites() {
90101
91102
async function loadList(sortingBy: SortingBy) {
92103
let tabSummary = null;
93-
if (props.type == TypeOfList.Today || props.type == TypeOfList.Dashboard)
94-
tabSummary = await useTodayTabListSummary(sortingBy);
95-
if (props.type == TypeOfList.All) {
96-
tabSummary = await useAllTabListSummary(sortingBy);
97-
98-
if (tabSummary != null) {
99-
firstDay.value = tabSummary.firstDay;
100-
countOfActiveDays.value = tabSummary.activeDaysTotal;
101-
dataForOvarallStats.value = tabSummary;
104+
105+
// Use shared data from Dashboard if available
106+
if (props.tabListData && (props.type == TypeOfList.Today || props.type == TypeOfList.Dashboard)) {
107+
tabSummary = props.tabListData;
108+
} else {
109+
// Otherwise fetch data as before
110+
if (props.type == TypeOfList.Today || props.type == TypeOfList.Dashboard)
111+
tabSummary = await useTodayTabListSummary(sortingBy);
112+
if (props.type == TypeOfList.All) {
113+
tabSummary = await useAllTabListSummary(sortingBy);
102114
}
103115
}
104-
116+
105117
if (tabSummary != null) {
118+
// Process All type specific data
119+
if (props.type == TypeOfList.All && tabSummary.firstDay) {
120+
firstDay.value = tabSummary.firstDay;
121+
countOfActiveDays.value = tabSummary.activeDaysTotal || 0;
122+
dataForOvarallStats.value = tabSummary;
123+
}
124+
125+
// Process common data
106126
loadedTabs = tabSummary.tabs;
107127
tabs.value = tabSummary.tabs;
108-
summaryTime.value = tabSummary.summaryTime;
109-
timeForChart.value = tabSummary.chart.timeForChart;
110-
sitesForChart.value = tabSummary.chart.sitesForChart;
128+
summaryTime.value = tabSummary.summaryTime || 0;
129+
130+
if (tabSummary.chart) {
131+
timeForChart.value = tabSummary.chart.timeForChart || [];
132+
sitesForChart.value = tabSummary.chart.sitesForChart || [];
133+
}
111134
135+
// Handle pagination for All type
112136
if (props.type == TypeOfList.All && loadedTabs.length > 100) {
113137
showOnlyFirst100Items.value = true;
114138
tabs.value = tabSummary.tabs.slice(0, 100);
@@ -151,6 +175,13 @@ function handleRefresh() {
151175
}
152176
}
153177
178+
// Watch for changes in the tabListData prop
179+
watch(() => props.tabListData, (newData) => {
180+
if (newData && (props.type == TypeOfList.Today || props.type == TypeOfList.Dashboard)) {
181+
loadList(SortingBy.UsageTime);
182+
}
183+
}, { deep: true });
184+
154185
onMounted(async () => {
155186
isLoading.value = true;
156187
await loadList(SortingBy.UsageTime);

src/components/TopSitesPieChart.vue

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,21 @@ import { Chart as ChartJS, ArcElement, Tooltip, Legend } from 'chart.js';
3030
import ChartDataLabels from 'chartjs-plugin-datalabels';
3131
import { convertSummaryTimeToString } from '../utils/converter';
3232
import { injectStorage } from '../storage/inject-storage';
33-
import { onMounted, onUnmounted, ref, watch } from 'vue';
33+
import { onMounted, onUnmounted, ref, watch, PropType } from 'vue';
3434
import { DARK_MODE_DEFAULT, StorageParams } from '../storage/storage-params';
3535
import { useTodayTabListSummary } from '../functions/useTodayTabListSummary';
3636
import { SortingBy } from '../utils/enums';
3737
import { Tab } from '../entity/tab';
3838
import { todayLocalDate } from '../utils/date';
39+
import { TabListSummary } from '../dto/tabListSummary';
40+
41+
// Define props
42+
const props = defineProps({
43+
tabListData: {
44+
type: Object as PropType<TabListSummary | null>,
45+
default: null
46+
}
47+
});
3948
4049
const settingsStorage = injectStorage();
4150
const darkMode = ref(false);
@@ -56,8 +65,8 @@ const chartColors = [
5665
async function processTabsData() {
5766
isLoading.value = true;
5867
59-
// Get today's tab list summary - same data source as used in TabList.vue
60-
const tabSummary = await useTodayTabListSummary(SortingBy.UsageTime);
68+
// Use the shared data from Dashboard if available, otherwise fetch it
69+
const tabSummary = props.tabListData || await useTodayTabListSummary(SortingBy.UsageTime);
6170
6271
if (!tabSummary || !tabSummary.tabs || tabSummary.tabs.length === 0) {
6372
isLoading.value = false;
@@ -148,6 +157,13 @@ function handleRefresh() {
148157
processTabsData();
149158
}
150159
160+
// Watch for changes in the tabListData prop
161+
watch(() => props.tabListData, (newData) => {
162+
if (newData) {
163+
processTabsData();
164+
}
165+
}, { deep: true });
166+
151167
onMounted(async () => {
152168
darkMode.value = await settingsStorage.getValue(StorageParams.DARK_MODE, DARK_MODE_DEFAULT);
153169
ChartJS.register(ArcElement, Tooltip, Legend, ChartDataLabels);

0 commit comments

Comments
 (0)