This commit is contained in:
parent
779500d22e
commit
42a78c529d
5 changed files with 74 additions and 5 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
const CACHE_NAME = 'agency-cache-v2';
|
const CACHE_NAME = 'agency-cache-v3';
|
||||||
const ASSETS = [
|
const ASSETS = [
|
||||||
'/',
|
'/',
|
||||||
'/index.html',
|
'/index.html',
|
||||||
|
|
@ -34,8 +34,16 @@ self.addEventListener('fetch', (event) => {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('push', (event) => {
|
self.addEventListener('push', (event) => {
|
||||||
const data = event.data ? event.data.json() : { title: 'Notification', body: 'New update from Agency' };
|
let data = { title: 'Notification', body: 'New update from Agency' };
|
||||||
|
try {
|
||||||
|
if (event.data) {
|
||||||
|
data = event.data.json();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error parsing push data:', e);
|
||||||
|
}
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
body: data.body,
|
body: data.body,
|
||||||
|
|
@ -44,7 +52,9 @@ self.addEventListener('push', (event) => {
|
||||||
vibrate: [100, 50, 100],
|
vibrate: [100, 50, 100],
|
||||||
data: {
|
data: {
|
||||||
dateOfArrival: Date.now(),
|
dateOfArrival: Date.now(),
|
||||||
primaryKey: '1'
|
primaryKey: '1',
|
||||||
|
taskId: data.task_id,
|
||||||
|
runId: data.run_id
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -55,7 +65,27 @@ self.addEventListener('push', (event) => {
|
||||||
|
|
||||||
self.addEventListener('notificationclick', (event) => {
|
self.addEventListener('notificationclick', (event) => {
|
||||||
event.notification.close();
|
event.notification.close();
|
||||||
|
|
||||||
|
const taskId = event.notification.data.taskId;
|
||||||
|
const runId = event.notification.data.runId;
|
||||||
|
|
||||||
|
let url = '/';
|
||||||
|
if (taskId && runId) {
|
||||||
|
url = `/?taskId=${taskId}&runId=${runId}`;
|
||||||
|
}
|
||||||
|
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
clients.openWindow('/')
|
clients.matchAll({ type: 'window', includeUncontrolled: true }).then((windowClients) => {
|
||||||
|
// Check if there is already a window open and focus it, or open a new one
|
||||||
|
for (let client of windowClients) {
|
||||||
|
if ('focus' in client) {
|
||||||
|
// Navigate the existing client to the new URL if it's the same app
|
||||||
|
return client.navigate(url).then(c => c.focus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (clients.openWindow) {
|
||||||
|
return clients.openWindow(url);
|
||||||
|
}
|
||||||
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,16 @@ async function fetchTasks() {
|
||||||
const response = await fetchWithAuth(`${API_URL}/tasks`);
|
const response = await fetchWithAuth(`${API_URL}/tasks`);
|
||||||
const newTasks = await response.json();
|
const newTasks = await response.json();
|
||||||
|
|
||||||
|
// Check for deep link in URL
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const urlTaskId = params.get('taskId');
|
||||||
|
const urlRunId = params.get('runId');
|
||||||
|
|
||||||
|
if (urlTaskId && !state.selectedTaskId) {
|
||||||
|
state.selectedTaskId = urlTaskId;
|
||||||
|
state.selectedRunId = urlRunId;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we should follow the latest run
|
// Check if we should follow the latest run
|
||||||
let newSelectedRunId = state.selectedRunId;
|
let newSelectedRunId = state.selectedRunId;
|
||||||
if (state.selectedTaskId) {
|
if (state.selectedTaskId) {
|
||||||
|
|
@ -179,6 +189,12 @@ async function fetchTasks() {
|
||||||
tasks: newTasks,
|
tasks: newTasks,
|
||||||
selectedRunId: newSelectedRunId
|
selectedRunId: newSelectedRunId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If we just loaded from a deep link, clear the params and select it
|
||||||
|
if (urlTaskId) {
|
||||||
|
window.history.replaceState({}, document.title, "/");
|
||||||
|
selectTask(urlTaskId, urlRunId);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching tasks:', error);
|
console.error('Error fetching tasks:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -806,6 +822,16 @@ async function initializeApp() {
|
||||||
if (hasSession) {
|
if (hasSession) {
|
||||||
appEl.classList.remove('hidden');
|
appEl.classList.remove('hidden');
|
||||||
loginOverlay.classList.add('hidden');
|
loginOverlay.classList.add('hidden');
|
||||||
|
|
||||||
|
// Handle deep links from notifications
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const taskId = params.get('taskId');
|
||||||
|
const runId = params.get('runId');
|
||||||
|
if (taskId) {
|
||||||
|
state.selectedTaskId = taskId;
|
||||||
|
state.selectedRunId = runId;
|
||||||
|
}
|
||||||
|
|
||||||
await fetchTasks();
|
await fetchTasks();
|
||||||
connectWebSocket();
|
connectWebSocket();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::error::AppResult;
|
use crate::error::AppResult;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
use web_push::*;
|
use web_push::*;
|
||||||
|
|
||||||
pub struct PushSender {
|
pub struct PushSender {
|
||||||
|
|
@ -56,6 +57,8 @@ impl PushSender {
|
||||||
subscription: &PushSubscription,
|
subscription: &PushSubscription,
|
||||||
title: &str,
|
title: &str,
|
||||||
body: &str,
|
body: &str,
|
||||||
|
task_id: Option<Uuid>,
|
||||||
|
run_id: Option<Uuid>,
|
||||||
) -> AppResult<()> {
|
) -> AppResult<()> {
|
||||||
let subscription_info = SubscriptionInfo::new(
|
let subscription_info = SubscriptionInfo::new(
|
||||||
subscription.endpoint.clone(),
|
subscription.endpoint.clone(),
|
||||||
|
|
@ -81,6 +84,8 @@ impl PushSender {
|
||||||
let payload = serde_json::to_vec(&serde_json::json!({
|
let payload = serde_json::to_vec(&serde_json::json!({
|
||||||
"title": title,
|
"title": title,
|
||||||
"body": body,
|
"body": body,
|
||||||
|
"task_id": task_id,
|
||||||
|
"run_id": run_id,
|
||||||
}))
|
}))
|
||||||
.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
.map_err(|e| crate::error::AppError::Internal(e.to_string()))?;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,13 @@ pub async fn execute_agent_run(
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = sender
|
if let Err(e) = sender
|
||||||
.send_notification(&sub_data, &format!("Task Completed: {}", status), &goal)
|
.send_notification(
|
||||||
|
&sub_data,
|
||||||
|
&format!("Task Completed: {}", status),
|
||||||
|
&goal,
|
||||||
|
Some(task_id),
|
||||||
|
Some(run_id),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
tracing::error!("Failed to send notification in background task: {}", e);
|
tracing::error!("Failed to send notification in background task: {}", e);
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,8 @@ impl Scheduler {
|
||||||
&sub_data,
|
&sub_data,
|
||||||
&format!("Scheduled Task Completed: {}", status),
|
&format!("Scheduled Task Completed: {}", status),
|
||||||
&goal,
|
&goal,
|
||||||
|
Some(task_id),
|
||||||
|
Some(run_id),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue