claude-code-templates 1.6.2 → 1.7.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/package.json +1 -1
- package/src/analytics.js +130 -1
- package/src/index.js +1 -1
package/package.json
CHANGED
package/src/analytics.js
CHANGED
|
@@ -1742,8 +1742,11 @@ async function createWebDashboard() {
|
|
|
1742
1742
|
</div>
|
|
1743
1743
|
</div>
|
|
1744
1744
|
<div class="chart-controls-right">
|
|
1745
|
+
<button class="refresh-btn" onclick="toggleNotifications()" id="notificationBtn">
|
|
1746
|
+
🔔 enable notifications
|
|
1747
|
+
</button>
|
|
1745
1748
|
<button class="refresh-btn" onclick="refreshCharts()" id="refreshBtn">
|
|
1746
|
-
refresh charts
|
|
1749
|
+
🔄 refresh charts
|
|
1747
1750
|
</button>
|
|
1748
1751
|
</div>
|
|
1749
1752
|
</div>
|
|
@@ -1833,6 +1836,8 @@ async function createWebDashboard() {
|
|
|
1833
1836
|
let tokenChart = null;
|
|
1834
1837
|
let projectChart = null;
|
|
1835
1838
|
let allData = null;
|
|
1839
|
+
let notificationsEnabled = false;
|
|
1840
|
+
let previousConversationStates = new Map();
|
|
1836
1841
|
|
|
1837
1842
|
async function loadData() {
|
|
1838
1843
|
try {
|
|
@@ -1860,6 +1865,9 @@ async function createWebDashboard() {
|
|
|
1860
1865
|
updateCharts(data);
|
|
1861
1866
|
updateSessionsTable();
|
|
1862
1867
|
|
|
1868
|
+
// Check for conversation state changes and send notifications
|
|
1869
|
+
checkForNotifications(data.conversations);
|
|
1870
|
+
|
|
1863
1871
|
} catch (error) {
|
|
1864
1872
|
document.getElementById('loading').style.display = 'none';
|
|
1865
1873
|
document.getElementById('error').style.display = 'block';
|
|
@@ -1867,6 +1875,108 @@ async function createWebDashboard() {
|
|
|
1867
1875
|
}
|
|
1868
1876
|
}
|
|
1869
1877
|
|
|
1878
|
+
// Notification functions
|
|
1879
|
+
async function requestNotificationPermission() {
|
|
1880
|
+
if (!('Notification' in window)) {
|
|
1881
|
+
console.log('This browser does not support notifications');
|
|
1882
|
+
return false;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
if (Notification.permission === 'granted') {
|
|
1886
|
+
notificationsEnabled = true;
|
|
1887
|
+
return true;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
if (Notification.permission !== 'denied') {
|
|
1891
|
+
const permission = await Notification.requestPermission();
|
|
1892
|
+
notificationsEnabled = permission === 'granted';
|
|
1893
|
+
return notificationsEnabled;
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
return false;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
function sendNotification(title, body, conversationId) {
|
|
1900
|
+
if (!notificationsEnabled) return;
|
|
1901
|
+
|
|
1902
|
+
const notification = new Notification(title, {
|
|
1903
|
+
body: body,
|
|
1904
|
+
icon: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIiByeD0iNCIgZmlsbD0iIzIxMjYyZCIvPgo8cGF0aCBkPSJNOCA4aDE2djE2SDh6IiBmaWxsPSIjZDU3NDU1Ii8+CjwvZGJnPgo=',
|
|
1905
|
+
badge: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iOCIgY3k9IjgiIHI9IjgiIGZpbGw9IiNkNTc0NTUiLz4KPC9zdmc+',
|
|
1906
|
+
tag: conversationId,
|
|
1907
|
+
requireInteraction: true
|
|
1908
|
+
});
|
|
1909
|
+
|
|
1910
|
+
notification.onclick = function() {
|
|
1911
|
+
window.focus();
|
|
1912
|
+
this.close();
|
|
1913
|
+
// Focus on the conversation if possible
|
|
1914
|
+
if (conversationId) {
|
|
1915
|
+
showSessionDetail(conversationId);
|
|
1916
|
+
}
|
|
1917
|
+
};
|
|
1918
|
+
|
|
1919
|
+
// Auto close after 10 seconds
|
|
1920
|
+
setTimeout(() => {
|
|
1921
|
+
notification.close();
|
|
1922
|
+
}, 10000);
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
function checkForNotifications(conversations) {
|
|
1926
|
+
if (!notificationsEnabled) return;
|
|
1927
|
+
|
|
1928
|
+
conversations.forEach(conv => {
|
|
1929
|
+
const currentState = conv.conversationState;
|
|
1930
|
+
const prevState = previousConversationStates.get(conv.id);
|
|
1931
|
+
|
|
1932
|
+
// Check if conversation state changed to "Awaiting user input..."
|
|
1933
|
+
if (prevState && prevState !== currentState) {
|
|
1934
|
+
if (currentState === 'Awaiting user input...' ||
|
|
1935
|
+
currentState === 'User may be typing...' ||
|
|
1936
|
+
currentState === 'Awaiting response...') {
|
|
1937
|
+
|
|
1938
|
+
const title = '🤖 Claude is waiting for you!';
|
|
1939
|
+
const body = \`Project: \${conv.project} - Claude needs your input\`;
|
|
1940
|
+
|
|
1941
|
+
sendNotification(title, body, conv.id);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
// Update previous state
|
|
1946
|
+
previousConversationStates.set(conv.id, currentState);
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
async function toggleNotifications() {
|
|
1951
|
+
const btn = document.getElementById('notificationBtn');
|
|
1952
|
+
|
|
1953
|
+
if (!notificationsEnabled) {
|
|
1954
|
+
const granted = await requestNotificationPermission();
|
|
1955
|
+
if (granted) {
|
|
1956
|
+
btn.textContent = '🔔 notifications on';
|
|
1957
|
+
btn.style.borderColor = '#3fb950';
|
|
1958
|
+
btn.style.color = '#3fb950';
|
|
1959
|
+
|
|
1960
|
+
// Send a test notification
|
|
1961
|
+
sendNotification(
|
|
1962
|
+
'🎉 Notifications enabled!',
|
|
1963
|
+
'You will now receive alerts when Claude is waiting for your input.',
|
|
1964
|
+
null
|
|
1965
|
+
);
|
|
1966
|
+
} else {
|
|
1967
|
+
btn.textContent = '🔕 notifications denied';
|
|
1968
|
+
btn.style.borderColor = '#f85149';
|
|
1969
|
+
btn.style.color = '#f85149';
|
|
1970
|
+
}
|
|
1971
|
+
} else {
|
|
1972
|
+
// Disable notifications
|
|
1973
|
+
notificationsEnabled = false;
|
|
1974
|
+
btn.textContent = '🔔 enable notifications';
|
|
1975
|
+
btn.style.borderColor = '#30363d';
|
|
1976
|
+
btn.style.color = '#7d8590';
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1870
1980
|
function updateStats(summary) {
|
|
1871
1981
|
document.getElementById('totalConversations').textContent = summary.totalConversations.toLocaleString();
|
|
1872
1982
|
document.getElementById('totalTokens').textContent = summary.totalTokens.toLocaleString();
|
|
@@ -2623,8 +2733,27 @@ async function createWebDashboard() {
|
|
|
2623
2733
|
// Add event listeners for date inputs
|
|
2624
2734
|
document.getElementById('dateFrom').addEventListener('change', refreshCharts);
|
|
2625
2735
|
document.getElementById('dateTo').addEventListener('change', refreshCharts);
|
|
2736
|
+
|
|
2737
|
+
// Initialize notification button state
|
|
2738
|
+
updateNotificationButtonState();
|
|
2626
2739
|
});
|
|
2627
2740
|
|
|
2741
|
+
function updateNotificationButtonState() {
|
|
2742
|
+
const btn = document.getElementById('notificationBtn');
|
|
2743
|
+
if (!btn) return;
|
|
2744
|
+
|
|
2745
|
+
if (Notification.permission === 'granted') {
|
|
2746
|
+
notificationsEnabled = true;
|
|
2747
|
+
btn.textContent = '🔔 notifications on';
|
|
2748
|
+
btn.style.borderColor = '#3fb950';
|
|
2749
|
+
btn.style.color = '#3fb950';
|
|
2750
|
+
} else if (Notification.permission === 'denied') {
|
|
2751
|
+
btn.textContent = '🔕 notifications denied';
|
|
2752
|
+
btn.style.borderColor = '#f85149';
|
|
2753
|
+
btn.style.color = '#f85149';
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2628
2757
|
// Add keyboard shortcut for refresh (F5 or Ctrl+R)
|
|
2629
2758
|
document.addEventListener('keydown', function(e) {
|
|
2630
2759
|
if (e.key === 'F5' || (e.ctrlKey && e.key === 'r')) {
|