@zumito-team/analytics-module 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/events/discord/MessageCreate.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +34 -4
- package/dist/models/ChannelMessageStats.d.ts +8 -0
- package/dist/models/ChannelMessageStats.js +31 -0
- package/dist/routes/AdminAnalytics.d.ts +1 -3
- package/dist/routes/AdminAnalytics.js +2 -23
- package/dist/routes/AdminAnalyticsCommands.d.ts +7 -0
- package/dist/routes/AdminAnalyticsCommands.js +34 -0
- package/dist/routes/AdminAnalyticsGrowth.d.ts +7 -0
- package/dist/routes/AdminAnalyticsGrowth.js +34 -0
- package/dist/routes/AdminAnalyticsMessages.d.ts +7 -0
- package/dist/routes/AdminAnalyticsMessages.js +32 -0
- package/dist/routes/UserPanelAnalytics.js +1 -17
- package/dist/routes/UserPanelAnalyticsCommands.d.ts +8 -0
- package/dist/routes/UserPanelAnalyticsCommands.js +48 -0
- package/dist/routes/UserPanelAnalyticsMessages.d.ts +8 -0
- package/dist/routes/UserPanelAnalyticsMessages.js +52 -0
- package/dist/routes/UserPanelAnalyticsVoice.d.ts +8 -0
- package/dist/routes/UserPanelAnalyticsVoice.js +53 -0
- package/dist/services/AnalyticsCollector.d.ts +5 -1
- package/dist/services/AnalyticsCollector.js +61 -3
- package/dist/views/admin-analytics-commands.ejs +55 -0
- package/dist/views/admin-analytics-growth.ejs +46 -0
- package/dist/views/admin-analytics-messages.ejs +30 -0
- package/dist/views/admin-analytics.ejs +38 -132
- package/dist/views/user-analytics-commands.ejs +55 -0
- package/dist/views/user-analytics-messages.ejs +47 -0
- package/dist/views/user-analytics-voice.ejs +47 -0
- package/dist/views/user-analytics.ejs +25 -166
- package/package.json +1 -1
|
@@ -1,37 +1,28 @@
|
|
|
1
1
|
<div class="p-4">
|
|
2
|
-
<div class="
|
|
2
|
+
<div class="mb-6">
|
|
3
3
|
<h1 class="text-2xl font-bold text-discord-foreground"><%= t('analytics.serverStats') %></h1>
|
|
4
|
-
<div class="flex gap-2">
|
|
5
|
-
<button data-days="7" class="date-btn btn-primary text-sm px-3 py-1 rounded"><%= t('analytics.last7days') %></button>
|
|
6
|
-
<button data-days="30" class="date-btn text-sm px-3 py-1 rounded bg-discord-dark-100 text-discord-foreground/70 hover:text-discord-foreground"><%= t('analytics.last30days') %></button>
|
|
7
|
-
<button data-days="90" class="date-btn text-sm px-3 py-1 rounded bg-discord-dark-100 text-discord-foreground/70 hover:text-discord-foreground"><%= t('analytics.last90days') %></button>
|
|
8
|
-
</div>
|
|
9
4
|
</div>
|
|
10
5
|
|
|
11
|
-
<div class="grid grid-cols-2 md:grid-cols-
|
|
6
|
+
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
|
12
7
|
<div class="card text-center">
|
|
13
|
-
<div class="text-2xl font-bold text-discord-
|
|
8
|
+
<div class="text-2xl font-bold text-discord-primary"><%= guildSummary.totalMessages %></div>
|
|
14
9
|
<div class="text-xs text-discord-foreground/60 mt-1"><%= t('analytics.messages') %></div>
|
|
15
10
|
</div>
|
|
16
11
|
<div class="card text-center">
|
|
17
|
-
<div class="text-2xl font-bold text-discord-
|
|
12
|
+
<div class="text-2xl font-bold text-discord-success"><%= guildSummary.totalCommands %></div>
|
|
18
13
|
<div class="text-xs text-discord-foreground/60 mt-1"><%= t('analytics.commands') %></div>
|
|
19
14
|
</div>
|
|
20
|
-
<div class="card text-center">
|
|
21
|
-
<div class="text-2xl font-bold text-discord-foreground"><%= guildSummary.totalJoins %></div>
|
|
22
|
-
<div class="text-xs text-discord-foreground/60 mt-1"><%= t('analytics.joins') %></div>
|
|
23
|
-
</div>
|
|
24
|
-
<div class="card text-center">
|
|
25
|
-
<div class="text-2xl font-bold text-discord-foreground"><%= guildSummary.totalLeaves %></div>
|
|
26
|
-
<div class="text-xs text-discord-foreground/60 mt-1"><%= t('analytics.leaves') %></div>
|
|
27
|
-
</div>
|
|
28
15
|
<div class="card text-center">
|
|
29
16
|
<div class="text-2xl font-bold text-discord-foreground"><%= Math.round(guildSummary.totalVoiceMinutes) %></div>
|
|
30
17
|
<div class="text-xs text-discord-foreground/60 mt-1"><%= t('analytics.voice') %> (min)</div>
|
|
31
18
|
</div>
|
|
19
|
+
<div class="card text-center">
|
|
20
|
+
<div class="text-2xl font-bold"><span class="text-discord-success"><%= guildSummary.totalJoins %></span> / <span class="text-discord-danger"><%= guildSummary.totalLeaves %></span></div>
|
|
21
|
+
<div class="text-xs text-discord-foreground/60 mt-1"><%= t('analytics.joins') %> / <%= t('analytics.leaves') %></div>
|
|
22
|
+
</div>
|
|
32
23
|
</div>
|
|
33
24
|
|
|
34
|
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-6
|
|
25
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
35
26
|
<div class="card">
|
|
36
27
|
<h3 class="text-lg font-semibold mb-4 text-discord-foreground"><%= t('analytics.messagesPerDay') %></h3>
|
|
37
28
|
<canvas id="chartMessages" width="400" height="200"></canvas>
|
|
@@ -40,170 +31,38 @@
|
|
|
40
31
|
<h3 class="text-lg font-semibold mb-4 text-discord-foreground"><%= t('analytics.joinsVsLeaves') %></h3>
|
|
41
32
|
<canvas id="chartMembers" width="400" height="200"></canvas>
|
|
42
33
|
</div>
|
|
43
|
-
<div class="card">
|
|
44
|
-
<h3 class="text-lg font-semibold mb-4 text-discord-foreground"><%= t('analytics.voiceActivity') %></h3>
|
|
45
|
-
<canvas id="chartVoice" width="400" height="200"></canvas>
|
|
46
|
-
</div>
|
|
47
|
-
<div class="card">
|
|
48
|
-
<h3 class="text-lg font-semibold mb-4 text-discord-foreground"><%= t('analytics.commandsPerDay') %></h3>
|
|
49
|
-
<canvas id="chartCommands" width="400" height="200"></canvas>
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
|
|
54
|
-
<div class="card">
|
|
55
|
-
<h3 class="text-lg font-semibold mb-4 text-discord-foreground"><%= t('analytics.topCommands') %></h3>
|
|
56
|
-
<canvas id="chartTopCommands" width="400" height="200"></canvas>
|
|
57
|
-
</div>
|
|
58
|
-
<% if (typeof slowestCommands !== 'undefined' && slowestCommands.length > 0) { %>
|
|
59
|
-
<div class="card">
|
|
60
|
-
<h3 class="text-lg font-semibold mb-4 text-discord-foreground"><%= t('analytics.slowestCommands') %></h3>
|
|
61
|
-
<canvas id="chartSlowestCommands" width="400" height="200"></canvas>
|
|
62
|
-
</div>
|
|
63
|
-
<% } %>
|
|
64
34
|
</div>
|
|
65
|
-
|
|
66
|
-
<% if (typeof channelVoice !== 'undefined' && channelVoice.length > 0) { %>
|
|
67
|
-
<div class="card mb-6">
|
|
68
|
-
<h3 class="text-lg font-semibold mb-4 text-discord-foreground"><%= t('analytics.perChannelVoice') %></h3>
|
|
69
|
-
<canvas id="chartChannelVoice" width="600" height="200"></canvas>
|
|
70
|
-
</div>
|
|
71
|
-
<% } %>
|
|
72
35
|
</div>
|
|
73
36
|
|
|
74
37
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
|
75
38
|
<script>
|
|
76
39
|
(function() {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
success: '#57f287',
|
|
80
|
-
warning: '#fee75c',
|
|
81
|
-
danger: '#ed4245',
|
|
82
|
-
foreground: '#ffffff',
|
|
83
|
-
foreground60: 'rgba(255,255,255,0.6)',
|
|
84
|
-
dark100: '#36393f',
|
|
85
|
-
dark200: '#2f3136',
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
Chart.defaults.color = colors.foreground60;
|
|
89
|
-
Chart.defaults.borderColor = colors.dark100;
|
|
90
|
-
Chart.defaults.plugins.legend.labels.color = colors.foreground60;
|
|
40
|
+
Chart.defaults.color = 'rgba(255,255,255,0.6)';
|
|
41
|
+
Chart.defaults.borderColor = '#36393f';
|
|
91
42
|
|
|
92
|
-
const
|
|
43
|
+
const messages = <%- JSON.stringify(messagesPerDay) %>;
|
|
44
|
+
const joins = <%- JSON.stringify(joinsPerDay) %>;
|
|
45
|
+
const leaves = <%- JSON.stringify(leavesPerDay) %>;
|
|
93
46
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
backgroundColor: colors.primary,
|
|
103
|
-
borderRadius: 4,
|
|
104
|
-
}]
|
|
105
|
-
},
|
|
106
|
-
options: { responsive: true, plugins: { legend: { display: false } } }
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function createHorizontalBarChart(canvasId, label, values, keyX, keyY) {
|
|
111
|
-
new Chart(document.getElementById(canvasId), {
|
|
112
|
-
type: 'bar',
|
|
113
|
-
data: {
|
|
114
|
-
labels: values.map(v => v[keyX]),
|
|
115
|
-
datasets: [{
|
|
116
|
-
label: label,
|
|
117
|
-
data: values.map(v => v[keyY]),
|
|
118
|
-
backgroundColor: values.map((_, i) => {
|
|
119
|
-
const alpha = 1 - (i * 0.08);
|
|
120
|
-
return `rgba(88,101,242,${Math.max(0.3, alpha)})`;
|
|
121
|
-
}),
|
|
122
|
-
borderRadius: 4,
|
|
123
|
-
}]
|
|
124
|
-
},
|
|
125
|
-
options: {
|
|
126
|
-
indexAxis: 'y',
|
|
127
|
-
responsive: true,
|
|
128
|
-
plugins: { legend: { display: false } }
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
createBarChart('chartMessages', '<%= t("analytics.messagesPerDay") %>', data.messagesPerDay, 'date', 'count');
|
|
134
|
-
createBarChart('chartVoice', '<%= t("analytics.voiceActivity") %>', data.voicePerDay, 'date', 'count');
|
|
135
|
-
createBarChart('chartCommands', '<%= t("analytics.commandsPerDay") %>', data.commandsPerDay, 'date', 'count');
|
|
136
|
-
createHorizontalBarChart('chartTopCommands', '<%= t("analytics.topCommands") %>', data.topCommands, 'command_name', 'usage_count');
|
|
47
|
+
new Chart(document.getElementById('chartMessages'), {
|
|
48
|
+
type: 'bar',
|
|
49
|
+
data: {
|
|
50
|
+
labels: messages.map(v => v.date),
|
|
51
|
+
datasets: [{ label: '<%= t("analytics.messages") %>', data: messages.map(v => v.count), backgroundColor: '#5865f2', borderRadius: 4 }]
|
|
52
|
+
},
|
|
53
|
+
options: { responsive: true, plugins: { legend: { display: false } } }
|
|
54
|
+
});
|
|
137
55
|
|
|
138
56
|
new Chart(document.getElementById('chartMembers'), {
|
|
139
57
|
type: 'line',
|
|
140
58
|
data: {
|
|
141
|
-
labels:
|
|
59
|
+
labels: joins.map(v => v.date),
|
|
142
60
|
datasets: [
|
|
143
|
-
{
|
|
144
|
-
|
|
145
|
-
data: data.joinsPerDay.map(v => v.count),
|
|
146
|
-
borderColor: colors.success,
|
|
147
|
-
backgroundColor: 'rgba(87,242,135,0.1)',
|
|
148
|
-
fill: true,
|
|
149
|
-
tension: 0.3,
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
label: '<%= t("analytics.leaves") %>',
|
|
153
|
-
data: data.leavesPerDay.map(v => v.count),
|
|
154
|
-
borderColor: colors.danger,
|
|
155
|
-
backgroundColor: 'rgba(237,66,69,0.1)',
|
|
156
|
-
fill: true,
|
|
157
|
-
tension: 0.3,
|
|
158
|
-
}
|
|
61
|
+
{ label: '<%= t("analytics.joins") %>', data: joins.map(v => v.count), borderColor: '#57f287', backgroundColor: 'rgba(87,242,135,0.1)', fill: true, tension: 0.3 },
|
|
62
|
+
{ label: '<%= t("analytics.leaves") %>', data: leaves.map(v => v.count), borderColor: '#ed4245', backgroundColor: 'rgba(237,66,69,0.1)', fill: true, tension: 0.3 },
|
|
159
63
|
]
|
|
160
64
|
},
|
|
161
65
|
options: { responsive: true }
|
|
162
66
|
});
|
|
163
|
-
|
|
164
|
-
<% if (typeof slowestCommands !== 'undefined' && slowestCommands.length > 0) { %>
|
|
165
|
-
new Chart(document.getElementById('chartSlowestCommands'), {
|
|
166
|
-
type: 'bar',
|
|
167
|
-
data: {
|
|
168
|
-
labels: data.slowestCommands.map(v => v.command_name),
|
|
169
|
-
datasets: [{
|
|
170
|
-
label: '<%= t("analytics.avgExecutionTime") %> (ms)',
|
|
171
|
-
data: data.slowestCommands.map(v => v.avgExecutionTimeMs),
|
|
172
|
-
backgroundColor: colors.warning,
|
|
173
|
-
borderRadius: 4,
|
|
174
|
-
}]
|
|
175
|
-
},
|
|
176
|
-
options: {
|
|
177
|
-
responsive: true,
|
|
178
|
-
plugins: { legend: { display: false } },
|
|
179
|
-
scales: { y: { title: { display: true, text: 'ms' } } }
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
<% } %>
|
|
183
|
-
|
|
184
|
-
<% if (typeof channelVoice !== 'undefined' && channelVoice.length > 0) { %>
|
|
185
|
-
new Chart(document.getElementById('chartChannelVoice'), {
|
|
186
|
-
type: 'bar',
|
|
187
|
-
data: {
|
|
188
|
-
labels: data.channelVoice.map(v => v.channel_id),
|
|
189
|
-
datasets: [{
|
|
190
|
-
label: '<%= t("analytics.totalMinutes") %>',
|
|
191
|
-
data: data.channelVoice.map(v => v.total_minutes),
|
|
192
|
-
backgroundColor: colors.primary,
|
|
193
|
-
borderRadius: 4,
|
|
194
|
-
}]
|
|
195
|
-
},
|
|
196
|
-
options: { responsive: true, plugins: { legend: { display: false } } }
|
|
197
|
-
});
|
|
198
|
-
<% } %>
|
|
199
|
-
|
|
200
|
-
document.querySelectorAll('.date-btn').forEach(btn => {
|
|
201
|
-
btn.addEventListener('click', () => {
|
|
202
|
-
const days = btn.dataset.days;
|
|
203
|
-
const currentUrl = new URL(window.location.href);
|
|
204
|
-
currentUrl.searchParams.set('days', days);
|
|
205
|
-
window.location.href = currentUrl.toString();
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
67
|
})();
|
|
209
68
|
</script>
|