DevelopedBy-Siva commited on
Commit
3c93545
·
1 Parent(s): 83cbd12
extension/manifest.json CHANGED
@@ -4,7 +4,11 @@
4
  "version": "0.1.0",
5
  "description": "AI workflow builder for Gmail-based small businesses.",
6
  "permissions": ["storage", "activeTab", "scripting"],
7
- "host_permissions": ["https://mail.google.com/*", "http://localhost:8000/*"],
 
 
 
 
8
  "background": {
9
  "service_worker": "background.js"
10
  },
 
4
  "version": "0.1.0",
5
  "description": "AI workflow builder for Gmail-based small businesses.",
6
  "permissions": ["storage", "activeTab", "scripting"],
7
+ "host_permissions": [
8
+ "https://mail.google.com/*",
9
+ "http://localhost:8000/*",
10
+ "https://*.hf.space/*"
11
+ ],
12
  "background": {
13
  "service_worker": "background.js"
14
  },
extension/sidebar/app.js ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { OnboardingScreen } from "./components/OnboardingScreen.js";
2
+ import { CategorizationScreen } from "./components/CategorizationScreen.js";
3
+ import { CustomTaskInput } from "./components/CustomTaskInput.js";
4
+ import { WorkflowPicker } from "./components/WorkflowPicker.js";
5
+ import { ConnectSheet } from "./components/ConnectSheet.js";
6
+ import { FileUpload } from "./components/FileUpload.js";
7
+ import { DeployingScreen } from "./components/DeployingScreen.js";
8
+ import { DashboardScreen } from "./components/DashboardScreen.js";
9
+ import { EscalationPanel } from "./components/EscalationPanel.js";
10
+ import { apiRequest } from "./hooks/useApi.js";
11
+ import { TaskCategoryGroup } from "./components/TaskCategoryGroup.js";
12
+
13
+ const root = document.getElementById("root");
14
+ const defaultDescription =
15
+ "I run an apple orchard. Customers email me orders, I check inventory in my Google Sheet, reply with pickup details, and every Friday I count weekly orders.";
16
+
17
+ const steps = [
18
+ OnboardingScreen(),
19
+ CategorizationScreen(),
20
+ CustomTaskInput(),
21
+ WorkflowPicker(),
22
+ ConnectSheet(),
23
+ FileUpload(),
24
+ DeployingScreen(),
25
+ DashboardScreen(),
26
+ EscalationPanel()
27
+ ];
28
+
29
+ root.innerHTML = `
30
+ <div class="sidebar-shell">
31
+ <header class="hero">
32
+ <p class="eyebrow">FlowPilot</p>
33
+ <h1>Build inbox automations without leaving Gmail</h1>
34
+ <p class="lede">Describe the business, choose workflows, and let the backend deploy them.</p>
35
+ </header>
36
+ <main class="screen-stack">${steps.join("")}</main>
37
+ </div>
38
+ `;
39
+
40
+ const backendUrlInput = document.getElementById("flowpilot-backend-url");
41
+ const saveUrlButton = document.getElementById("flowpilot-save-url");
42
+ const descriptionInput = document.getElementById("flowpilot-business-description");
43
+ const analyzeButton = document.getElementById("flowpilot-analyze-button");
44
+ const onboardingStatus = document.getElementById("flowpilot-onboarding-status");
45
+ const summary = document.getElementById("flowpilot-summary");
46
+ const categories = document.getElementById("flowpilot-categories");
47
+
48
+ init();
49
+
50
+ async function init() {
51
+ const stored = await chrome.storage.local.get("flowpilotBackendUrl");
52
+ backendUrlInput.value = stored.flowpilotBackendUrl || "https://technophyle-flow-pilot.hf.space/api";
53
+ descriptionInput.value = defaultDescription;
54
+
55
+ saveUrlButton.addEventListener("click", saveBackendUrl);
56
+ analyzeButton.addEventListener("click", analyzeBusiness);
57
+ }
58
+
59
+ async function saveBackendUrl() {
60
+ const nextUrl = backendUrlInput.value.trim().replace(/\/$/, "");
61
+ if (!nextUrl) {
62
+ setStatus("Enter a backend URL ending in /api.", true);
63
+ return;
64
+ }
65
+ await chrome.storage.local.set({ flowpilotBackendUrl: nextUrl });
66
+ setStatus(`Backend saved: ${nextUrl}`);
67
+ }
68
+
69
+ async function analyzeBusiness() {
70
+ const description = descriptionInput.value.trim();
71
+ if (!description) {
72
+ setStatus("Add a short business description before running analysis.", true);
73
+ return;
74
+ }
75
+
76
+ analyzeButton.disabled = true;
77
+ analyzeButton.textContent = "Analyzing...";
78
+ setStatus("Running analysis against the configured backend.");
79
+
80
+ try {
81
+ await saveBackendUrl();
82
+ const payload = await apiRequest("/analyze", {
83
+ method: "POST",
84
+ body: JSON.stringify({
85
+ owner_id: "extension-demo-owner",
86
+ owner_email: "owner@example.com",
87
+ description
88
+ })
89
+ });
90
+ renderAnalysis(payload);
91
+ setStatus("Analysis loaded into the extension.");
92
+ } catch (error) {
93
+ setStatus(error.message || "Could not reach the backend.", true);
94
+ } finally {
95
+ analyzeButton.disabled = false;
96
+ analyzeButton.textContent = "Analyze My Process";
97
+ }
98
+ }
99
+
100
+ function renderAnalysis(payload) {
101
+ summary.textContent = payload.summary || "Analysis complete.";
102
+ categories.innerHTML = [
103
+ TaskCategoryGroup(
104
+ "Can Be Fully Automated",
105
+ (payload.tasks?.fully_automatable || []).map((task) => task.name)
106
+ ),
107
+ TaskCategoryGroup(
108
+ "AI-Assisted",
109
+ (payload.tasks?.ai_assisted || []).map((task) => task.name)
110
+ ),
111
+ TaskCategoryGroup(
112
+ "Keep Manual",
113
+ (payload.tasks?.manual || []).map((task) => task.name)
114
+ )
115
+ ].join("");
116
+ }
117
+
118
+ function setStatus(message, isError = false) {
119
+ onboardingStatus.textContent = message;
120
+ onboardingStatus.classList.toggle("error-copy", isError);
121
+ }
extension/sidebar/app.jsx DELETED
@@ -1,34 +0,0 @@
1
- import { OnboardingScreen } from "./components/OnboardingScreen.jsx";
2
- import { CategorizationScreen } from "./components/CategorizationScreen.jsx";
3
- import { CustomTaskInput } from "./components/CustomTaskInput.jsx";
4
- import { WorkflowPicker } from "./components/WorkflowPicker.jsx";
5
- import { ConnectSheet } from "./components/ConnectSheet.jsx";
6
- import { FileUpload } from "./components/FileUpload.jsx";
7
- import { DeployingScreen } from "./components/DeployingScreen.jsx";
8
- import { DashboardScreen } from "./components/DashboardScreen.jsx";
9
- import { EscalationPanel } from "./components/EscalationPanel.jsx";
10
-
11
- const root = document.getElementById("root");
12
-
13
- const steps = [
14
- OnboardingScreen(),
15
- CategorizationScreen(),
16
- CustomTaskInput(),
17
- WorkflowPicker(),
18
- ConnectSheet(),
19
- FileUpload(),
20
- DeployingScreen(),
21
- DashboardScreen(),
22
- EscalationPanel()
23
- ];
24
-
25
- root.innerHTML = `
26
- <div class="sidebar-shell">
27
- <header class="hero">
28
- <p class="eyebrow">FlowPilot</p>
29
- <h1>Build inbox automations without leaving Gmail</h1>
30
- <p class="lede">Describe the business, choose workflows, and let the backend deploy them.</p>
31
- </header>
32
- <main class="screen-stack">${steps.join("")}</main>
33
- </div>
34
- `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
extension/sidebar/components/{CategorizationScreen.jsx → CategorizationScreen.js} RENAMED
@@ -1,13 +1,10 @@
1
- import { TaskCategoryGroup } from "./TaskCategoryGroup.jsx";
2
-
3
  export function CategorizationScreen() {
4
  return `
5
- <section class="screen-card">
6
  <div class="step-label">2. AI Categorization</div>
7
  <h2>Here’s what FlowPilot found</h2>
8
- ${TaskCategoryGroup("Can Be Fully Automated", ["Order processing", "Weekly order summary report"])}
9
- ${TaskCategoryGroup("AI-Assisted", ["Availability inquiries", "Low inventory alerts"])}
10
- ${TaskCategoryGroup("Keep Manual", ["Custom requests", "VIP relationship messages"])}
11
  </section>
12
  `;
13
  }
 
 
 
1
  export function CategorizationScreen() {
2
  return `
3
+ <section class="screen-card" id="flowpilot-categorization-card">
4
  <div class="step-label">2. AI Categorization</div>
5
  <h2>Here’s what FlowPilot found</h2>
6
+ <p id="flowpilot-summary" class="muted">Run the analysis above to load real recommendations from the backend.</p>
7
+ <div id="flowpilot-categories"></div>
 
8
  </section>
9
  `;
10
  }
extension/sidebar/components/{ConnectSheet.jsx → ConnectSheet.js} RENAMED
File without changes
extension/sidebar/components/{CustomTaskInput.jsx → CustomTaskInput.js} RENAMED
File without changes
extension/sidebar/components/{DashboardScreen.jsx → DashboardScreen.js} RENAMED
@@ -1,4 +1,4 @@
1
- import { StatusBadge } from "./StatusBadge.jsx";
2
 
3
  export function DashboardScreen() {
4
  return `
 
1
+ import { StatusBadge } from "./StatusBadge.js";
2
 
3
  export function DashboardScreen() {
4
  return `
extension/sidebar/components/{DeployingScreen.jsx → DeployingScreen.js} RENAMED
File without changes
extension/sidebar/components/{EscalationPanel.jsx → EscalationPanel.js} RENAMED
File without changes
extension/sidebar/components/{FileUpload.jsx → FileUpload.js} RENAMED
File without changes
extension/sidebar/components/OnboardingScreen.js ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function OnboardingScreen() {
2
+ return `
3
+ <section class="screen-card">
4
+ <div class="step-label">1. Describe Business</div>
5
+ <h2>What does your business handle every day?</h2>
6
+ <label class="field-label" for="flowpilot-backend-url">Backend URL</label>
7
+ <input
8
+ id="flowpilot-backend-url"
9
+ class="text-input"
10
+ placeholder="https://technophyle-flow-pilot.hf.space/api"
11
+ />
12
+ <div class="button-row">
13
+ <button id="flowpilot-save-url" class="ghost-button">Save URL</button>
14
+ </div>
15
+ <label class="field-label" for="flowpilot-business-description">Business Description</label>
16
+ <textarea
17
+ id="flowpilot-business-description"
18
+ class="input-area"
19
+ placeholder="I run an apple orchard. Customers email me orders..."
20
+ ></textarea>
21
+ <div class="button-row">
22
+ <button id="flowpilot-analyze-button" class="primary-button">Analyze My Process</button>
23
+ </div>
24
+ <p id="flowpilot-onboarding-status" class="muted status-copy">Connect the extension to your backend, then run analysis.</p>
25
+ </section>
26
+ `;
27
+ }
extension/sidebar/components/OnboardingScreen.jsx DELETED
@@ -1,10 +0,0 @@
1
- export function OnboardingScreen() {
2
- return `
3
- <section class="screen-card">
4
- <div class="step-label">1. Describe Business</div>
5
- <h2>What does your business handle every day?</h2>
6
- <textarea class="input-area" placeholder="I run an apple orchard. Customers email me orders..."></textarea>
7
- <button class="primary-button">Analyze My Process</button>
8
- </section>
9
- `;
10
- }
 
 
 
 
 
 
 
 
 
 
 
extension/sidebar/components/{StatusBadge.jsx → StatusBadge.js} RENAMED
File without changes
extension/sidebar/components/{TaskCategoryGroup.jsx → TaskCategoryGroup.js} RENAMED
File without changes
extension/sidebar/components/{WorkflowCard.jsx → WorkflowCard.js} RENAMED
File without changes
extension/sidebar/components/{WorkflowPicker.jsx → WorkflowPicker.js} RENAMED
@@ -1,4 +1,4 @@
1
- import { WorkflowCard } from "./WorkflowCard.jsx";
2
 
3
  export function WorkflowPicker() {
4
  return `
 
1
+ import { WorkflowCard } from "./WorkflowCard.js";
2
 
3
  export function WorkflowPicker() {
4
  return `
extension/sidebar/hooks/useApi.js CHANGED
@@ -5,5 +5,10 @@ export async function apiRequest(path, options = {}) {
5
  headers: { "Content-Type": "application/json" },
6
  ...options
7
  });
8
- return response.json();
 
 
 
 
 
9
  }
 
5
  headers: { "Content-Type": "application/json" },
6
  ...options
7
  });
8
+ const data = await response.json().catch(() => ({}));
9
+ if (!response.ok) {
10
+ const message = data?.detail || `Request failed with status ${response.status}`;
11
+ throw new Error(message);
12
+ }
13
+ return data;
14
  }
extension/sidebar/index.html CHANGED
@@ -8,6 +8,6 @@
8
  </head>
9
  <body>
10
  <div id="root"></div>
11
- <script type="module" src="./app.jsx"></script>
12
  </body>
13
  </html>
 
8
  </head>
9
  <body>
10
  <div id="root"></div>
11
+ <script type="module" src="./app.js"></script>
12
  </body>
13
  </html>
extension/sidebar/styles/sidebar.css CHANGED
@@ -82,12 +82,28 @@ body {
82
  min-height: 128px;
83
  }
84
 
 
 
 
 
 
 
 
 
 
 
85
  .workflow-grid,
86
  .action-row {
87
  display: grid;
88
  gap: 12px;
89
  }
90
 
 
 
 
 
 
 
91
  .dashboard-row,
92
  .status-row {
93
  display: flex;
@@ -127,6 +143,14 @@ body {
127
  width: 100%;
128
  }
129
 
 
 
 
 
 
 
 
 
130
  .status-badge {
131
  display: inline-flex;
132
  align-items: center;
 
82
  min-height: 128px;
83
  }
84
 
85
+ .field-label {
86
+ display: block;
87
+ margin: 14px 0 8px;
88
+ font-size: 12px;
89
+ font-weight: 600;
90
+ color: var(--muted);
91
+ text-transform: uppercase;
92
+ letter-spacing: 0.06em;
93
+ }
94
+
95
  .workflow-grid,
96
  .action-row {
97
  display: grid;
98
  gap: 12px;
99
  }
100
 
101
+ .button-row {
102
+ display: flex;
103
+ gap: 10px;
104
+ margin-top: 12px;
105
+ }
106
+
107
  .dashboard-row,
108
  .status-row {
109
  display: flex;
 
143
  width: 100%;
144
  }
145
 
146
+ .status-copy {
147
+ margin: 12px 0 0;
148
+ }
149
+
150
+ .error-copy {
151
+ color: #9e2f1f;
152
+ }
153
+
154
  .status-badge {
155
  display: inline-flex;
156
  align-items: center;