Spaces:
Sleeping
Sleeping
DevelopedBy-Siva commited on
Commit ·
d28fc5d
1
Parent(s): 3c93545
refactor UI
Browse files- extension/content.js +33 -1
- extension/sidebar/app.js +21 -2
- extension/sidebar/components/DashboardScreen.js +2 -1
- extension/sidebar/components/DeployingScreen.js +2 -1
- extension/sidebar/components/OnboardingScreen.js +1 -0
- extension/sidebar/components/TaskCategoryGroup.js +14 -2
- extension/sidebar/components/WorkflowCard.js +2 -1
- extension/sidebar/components/WorkflowPicker.js +1 -0
- extension/sidebar/styles/sidebar.css +11 -0
extension/content.js
CHANGED
|
@@ -1,5 +1,24 @@
|
|
| 1 |
function injectSidebar() {
|
| 2 |
if (document.getElementById("flowpilot-sidebar-frame")) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
const frame = document.createElement("iframe");
|
| 4 |
frame.id = "flowpilot-sidebar-frame";
|
| 5 |
frame.src = chrome.runtime.getURL("sidebar/index.html");
|
|
@@ -12,8 +31,21 @@ function injectSidebar() {
|
|
| 12 |
border: "0",
|
| 13 |
zIndex: "999999",
|
| 14 |
boxShadow: "0 0 24px rgba(0,0,0,0.15)",
|
| 15 |
-
background: "#f7f2e8"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
});
|
|
|
|
|
|
|
| 17 |
document.body.appendChild(frame);
|
| 18 |
}
|
| 19 |
|
|
|
|
| 1 |
function injectSidebar() {
|
| 2 |
if (document.getElementById("flowpilot-sidebar-frame")) return;
|
| 3 |
+
|
| 4 |
+
const launcher = document.createElement("button");
|
| 5 |
+
launcher.id = "flowpilot-sidebar-toggle";
|
| 6 |
+
launcher.textContent = "FlowPilot";
|
| 7 |
+
Object.assign(launcher.style, {
|
| 8 |
+
position: "fixed",
|
| 9 |
+
top: "16px",
|
| 10 |
+
right: "16px",
|
| 11 |
+
zIndex: "1000000",
|
| 12 |
+
border: "0",
|
| 13 |
+
borderRadius: "999px",
|
| 14 |
+
padding: "10px 14px",
|
| 15 |
+
background: "#a44a1f",
|
| 16 |
+
color: "#fff7f0",
|
| 17 |
+
font: '600 13px Georgia, "Times New Roman", serif',
|
| 18 |
+
cursor: "pointer",
|
| 19 |
+
boxShadow: "0 12px 28px rgba(0,0,0,0.18)"
|
| 20 |
+
});
|
| 21 |
+
|
| 22 |
const frame = document.createElement("iframe");
|
| 23 |
frame.id = "flowpilot-sidebar-frame";
|
| 24 |
frame.src = chrome.runtime.getURL("sidebar/index.html");
|
|
|
|
| 31 |
border: "0",
|
| 32 |
zIndex: "999999",
|
| 33 |
boxShadow: "0 0 24px rgba(0,0,0,0.15)",
|
| 34 |
+
background: "#f7f2e8",
|
| 35 |
+
transform: "translateX(100%)",
|
| 36 |
+
transition: "transform 180ms ease",
|
| 37 |
+
pointerEvents: "none"
|
| 38 |
+
});
|
| 39 |
+
|
| 40 |
+
let isOpen = false;
|
| 41 |
+
launcher.addEventListener("click", () => {
|
| 42 |
+
isOpen = !isOpen;
|
| 43 |
+
frame.style.transform = isOpen ? "translateX(0)" : "translateX(100%)";
|
| 44 |
+
frame.style.pointerEvents = isOpen ? "auto" : "none";
|
| 45 |
+
launcher.textContent = isOpen ? "Close FlowPilot" : "FlowPilot";
|
| 46 |
});
|
| 47 |
+
|
| 48 |
+
document.body.appendChild(launcher);
|
| 49 |
document.body.appendChild(frame);
|
| 50 |
}
|
| 51 |
|
extension/sidebar/app.js
CHANGED
|
@@ -60,10 +60,15 @@ 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() {
|
|
@@ -78,7 +83,10 @@ async function analyzeBusiness() {
|
|
| 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({
|
|
@@ -119,3 +127,14 @@ function setStatus(message, isError = false) {
|
|
| 119 |
onboardingStatus.textContent = message;
|
| 120 |
onboardingStatus.classList.toggle("error-copy", isError);
|
| 121 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
const nextUrl = backendUrlInput.value.trim().replace(/\/$/, "");
|
| 61 |
if (!nextUrl) {
|
| 62 |
setStatus("Enter a backend URL ending in /api.", true);
|
| 63 |
+
return false;
|
| 64 |
+
}
|
| 65 |
+
if (!isSupportedBackendUrl(nextUrl)) {
|
| 66 |
+
setStatus("Use either http://localhost:8000/api or an https://...hf.space/api backend.", true);
|
| 67 |
+
return false;
|
| 68 |
}
|
| 69 |
await chrome.storage.local.set({ flowpilotBackendUrl: nextUrl });
|
| 70 |
setStatus(`Backend saved: ${nextUrl}`);
|
| 71 |
+
return true;
|
| 72 |
}
|
| 73 |
|
| 74 |
async function analyzeBusiness() {
|
|
|
|
| 83 |
setStatus("Running analysis against the configured backend.");
|
| 84 |
|
| 85 |
try {
|
| 86 |
+
const saved = await saveBackendUrl();
|
| 87 |
+
if (!saved) {
|
| 88 |
+
return;
|
| 89 |
+
}
|
| 90 |
const payload = await apiRequest("/analyze", {
|
| 91 |
method: "POST",
|
| 92 |
body: JSON.stringify({
|
|
|
|
| 127 |
onboardingStatus.textContent = message;
|
| 128 |
onboardingStatus.classList.toggle("error-copy", isError);
|
| 129 |
}
|
| 130 |
+
|
| 131 |
+
function isSupportedBackendUrl(value) {
|
| 132 |
+
try {
|
| 133 |
+
const url = new URL(value);
|
| 134 |
+
const isLocal = url.protocol === "http:" && url.hostname === "localhost" && url.pathname === "/api";
|
| 135 |
+
const isSpace = url.protocol === "https:" && url.hostname.endsWith(".hf.space") && url.pathname === "/api";
|
| 136 |
+
return isLocal || isSpace;
|
| 137 |
+
} catch {
|
| 138 |
+
return false;
|
| 139 |
+
}
|
| 140 |
+
}
|
extension/sidebar/components/DashboardScreen.js
CHANGED
|
@@ -4,7 +4,8 @@ export function DashboardScreen() {
|
|
| 4 |
return `
|
| 5 |
<section class="screen-card">
|
| 6 |
<div class="step-label">8. Dashboard</div>
|
| 7 |
-
<h2>
|
|
|
|
| 8 |
<div class="dashboard-row">
|
| 9 |
<span>3 active workflows</span>
|
| 10 |
${StatusBadge("active")}
|
|
|
|
| 4 |
return `
|
| 5 |
<section class="screen-card">
|
| 6 |
<div class="step-label">8. Dashboard</div>
|
| 7 |
+
<h2>Dashboard Preview</h2>
|
| 8 |
+
<p class="muted">Real workflow health and counts will appear here after deploy/status wiring.</p>
|
| 9 |
<div class="dashboard-row">
|
| 10 |
<span>3 active workflows</span>
|
| 11 |
${StatusBadge("active")}
|
extension/sidebar/components/DeployingScreen.js
CHANGED
|
@@ -2,7 +2,8 @@ export function DeployingScreen() {
|
|
| 2 |
return `
|
| 3 |
<section class="screen-card">
|
| 4 |
<div class="step-label">7. Deploy</div>
|
| 5 |
-
<h2>
|
|
|
|
| 6 |
<ul class="status-list">
|
| 7 |
<li>Order Processing (Full Auto) deployed</li>
|
| 8 |
<li>Weekly Order Summary deployed for Fridays at 8:00 AM</li>
|
|
|
|
| 2 |
return `
|
| 3 |
<section class="screen-card">
|
| 4 |
<div class="step-label">7. Deploy</div>
|
| 5 |
+
<h2>Deployment Preview</h2>
|
| 6 |
+
<p class="muted">This section is a visual stub until deploy actions are connected.</p>
|
| 7 |
<ul class="status-list">
|
| 8 |
<li>Order Processing (Full Auto) deployed</li>
|
| 9 |
<li>Weekly Order Summary deployed for Fridays at 8:00 AM</li>
|
extension/sidebar/components/OnboardingScreen.js
CHANGED
|
@@ -9,6 +9,7 @@ export function OnboardingScreen() {
|
|
| 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>
|
|
|
|
| 9 |
class="text-input"
|
| 10 |
placeholder="https://technophyle-flow-pilot.hf.space/api"
|
| 11 |
/>
|
| 12 |
+
<p class="muted helper-copy">Supported today: localhost for development or a *.hf.space/api backend.</p>
|
| 13 |
<div class="button-row">
|
| 14 |
<button id="flowpilot-save-url" class="ghost-button">Save URL</button>
|
| 15 |
</div>
|
extension/sidebar/components/TaskCategoryGroup.js
CHANGED
|
@@ -1,10 +1,22 @@
|
|
| 1 |
export function TaskCategoryGroup(title, items) {
|
|
|
|
|
|
|
|
|
|
| 2 |
return `
|
| 3 |
<div class="category-group">
|
| 4 |
-
<p class="group-title">${title}</p>
|
| 5 |
<ul>
|
| 6 |
-
${
|
| 7 |
</ul>
|
| 8 |
</div>
|
| 9 |
`;
|
| 10 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
export function TaskCategoryGroup(title, items) {
|
| 2 |
+
const safeItems = items.length
|
| 3 |
+
? items.map((item) => `<li><label><input type="checkbox" checked /> ${escapeHtml(item)}</label></li>`).join("")
|
| 4 |
+
: `<li class="muted">No tasks in this category yet.</li>`;
|
| 5 |
return `
|
| 6 |
<div class="category-group">
|
| 7 |
+
<p class="group-title">${escapeHtml(title)}</p>
|
| 8 |
<ul>
|
| 9 |
+
${safeItems}
|
| 10 |
</ul>
|
| 11 |
</div>
|
| 12 |
`;
|
| 13 |
}
|
| 14 |
+
|
| 15 |
+
function escapeHtml(value) {
|
| 16 |
+
return String(value)
|
| 17 |
+
.replaceAll("&", "&")
|
| 18 |
+
.replaceAll("<", "<")
|
| 19 |
+
.replaceAll(">", ">")
|
| 20 |
+
.replaceAll('"', """)
|
| 21 |
+
.replaceAll("'", "'");
|
| 22 |
+
}
|
extension/sidebar/components/WorkflowCard.js
CHANGED
|
@@ -7,7 +7,8 @@ export function WorkflowCard(title, mode, steps, ownerInvolvement) {
|
|
| 7 |
${steps.map((step) => `<li>${step}</li>`).join("")}
|
| 8 |
</ul>
|
| 9 |
<p class="muted">You do: ${ownerInvolvement}</p>
|
| 10 |
-
<button class="primary-button small-button">Choose</button>
|
|
|
|
| 11 |
</article>
|
| 12 |
`;
|
| 13 |
}
|
|
|
|
| 7 |
${steps.map((step) => `<li>${step}</li>`).join("")}
|
| 8 |
</ul>
|
| 9 |
<p class="muted">You do: ${ownerInvolvement}</p>
|
| 10 |
+
<button class="primary-button small-button" disabled>Choose</button>
|
| 11 |
+
<p class="muted helper-copy">Preview only. Workflow selection is the next wiring step.</p>
|
| 12 |
</article>
|
| 13 |
`;
|
| 14 |
}
|
extension/sidebar/components/WorkflowPicker.js
CHANGED
|
@@ -5,6 +5,7 @@ export function WorkflowPicker() {
|
|
| 5 |
<section class="screen-card">
|
| 6 |
<div class="step-label">4. Pick Workflows</div>
|
| 7 |
<h2>Order Processing</h2>
|
|
|
|
| 8 |
<div class="workflow-grid">
|
| 9 |
${WorkflowCard("Workflow A", "Full Auto", ["AI extracts order", "Checks sheet inventory", "Updates sheet and replies"], "Nothing unless alerted")}
|
| 10 |
${WorkflowCard("Workflow B", "Review First", ["AI extracts order", "Shows summary in sidebar", "You approve before sending"], "One click per order")}
|
|
|
|
| 5 |
<section class="screen-card">
|
| 6 |
<div class="step-label">4. Pick Workflows</div>
|
| 7 |
<h2>Order Processing</h2>
|
| 8 |
+
<p class="muted">These cards are illustrative until we wire real workflow suggestions from the backend.</p>
|
| 9 |
<div class="workflow-grid">
|
| 10 |
${WorkflowCard("Workflow A", "Full Auto", ["AI extracts order", "Checks sheet inventory", "Updates sheet and replies"], "Nothing unless alerted")}
|
| 11 |
${WorkflowCard("Workflow B", "Review First", ["AI extracts order", "Shows summary in sidebar", "You approve before sending"], "One click per order")}
|
extension/sidebar/styles/sidebar.css
CHANGED
|
@@ -147,6 +147,12 @@ body {
|
|
| 147 |
margin: 12px 0 0;
|
| 148 |
}
|
| 149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
.error-copy {
|
| 151 |
color: #9e2f1f;
|
| 152 |
}
|
|
@@ -171,6 +177,11 @@ body {
|
|
| 171 |
padding: 18px;
|
| 172 |
}
|
| 173 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 174 |
ul {
|
| 175 |
padding-left: 18px;
|
| 176 |
}
|
|
|
|
| 147 |
margin: 12px 0 0;
|
| 148 |
}
|
| 149 |
|
| 150 |
+
.helper-copy {
|
| 151 |
+
margin: 8px 0 0;
|
| 152 |
+
font-size: 12px;
|
| 153 |
+
line-height: 1.5;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
.error-copy {
|
| 157 |
color: #9e2f1f;
|
| 158 |
}
|
|
|
|
| 177 |
padding: 18px;
|
| 178 |
}
|
| 179 |
|
| 180 |
+
button[disabled] {
|
| 181 |
+
cursor: not-allowed;
|
| 182 |
+
opacity: 0.55;
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
ul {
|
| 186 |
padding-left: 18px;
|
| 187 |
}
|