
Scripts are ready-to-use tasks that do things automatically for you.
You can run scripts whenever you need them - like generating a report, sending notifications, or processing data.
', + onNextClick: async () => { + // Move to the next step (Flows) + setTimeout(() => { + const flowsButton = document.querySelector('[data-value="flow"]') as HTMLElement | null + + if (flowsButton) { + driver.moveNext() + } else { + driver.moveNext() + } + }, 100) + } + }, + element: '[data-value="script"]' + }, + { + popover: { + title: 'Flows - Run step-by-step processes', + description: + '
Flows are processes that run multiple tasks in order, one after another.
You can start a flow and watch it complete each step automatically - perfect for tasks that have multiple stages.
', + onNextClick: async () => { + // Move to the next step (Apps) + setTimeout(() => { + const appsButton = document.querySelector('[data-value="app"]') as HTMLElement | null + + if (appsButton) { + driver.moveNext() + } else { + driver.moveNext() + } + }, 100) + } + }, + element: '[data-value="flow"]' + }, + { + popover: { + title: 'Apps - Use custom tools', + description: + '
Apps are easy-to-use tools with buttons, forms, and displays built just for your team.
You can open an app to work with your data, fill out forms, or trigger tasks - no technical knowledge needed!
', + onNextClick: async () => { + // Move to the next step (cursor animation) + driver.moveNext() + } + }, + element: '[data-value="app"]' + }, + { + popover: { + title: 'Finally, the Menu section', + description: 'Explore available tabs where you can access your history of runs, your scheduled scripts, your tutorials progress etc.💡 Want to learn more? Access more tutorials from the Tutorials page in the main menu.
', + onNextClick: async () => { + // Find the target button and click it + const targetButton = document.querySelector('[role="menuitem"]') as HTMLElement | null + if (targetButton) { + targetButton.click() + } + + // Wait for menu to open + await wait(DELAY_MEDIUM) + + // Mark tutorial as complete + updateProgress(index) + driver.destroy() + + // Clean up URL parameter if present + if ($page.url.searchParams.has('tutorial')) { + goto(`${base}/`, { replaceState: true }) + } + } + }, + element: '[role="menuitem"]' + } + ] + + return steps + }} +/> diff --git a/frontend/src/lib/tutorialUtils.ts b/frontend/src/lib/tutorialUtils.ts index bd0ce09352..02222138e8 100644 --- a/frontend/src/lib/tutorialUtils.ts +++ b/frontend/src/lib/tutorialUtils.ts @@ -71,11 +71,6 @@ export async function skipAllTodos() { tutorialsToDo.set([]) skippedAll.set(true) - // Dismiss the tutorial banner when all tutorials are skipped - if (typeof window !== 'undefined') { - localStorage.setItem(TUTORIAL_BANNER_DISMISSED_KEY, 'true') - } - await UserService.updateTutorialProgress({ requestBody: { progress: bits, skipped_all: true } }) } diff --git a/frontend/src/lib/tutorials/config.ts b/frontend/src/lib/tutorials/config.ts index 3aa062e346..455c4c50e3 100644 --- a/frontend/src/lib/tutorials/config.ts +++ b/frontend/src/lib/tutorials/config.ts @@ -1,5 +1,5 @@ import type { ComponentType } from 'svelte' -import { Workflow, GraduationCap, Wrench, PlayCircle, Link2 } from 'lucide-svelte' +import { Workflow, GraduationCap, Wrench, PlayCircle, Link2, History } from 'lucide-svelte' import { base } from '$lib/base' import type { Role } from './roleUtils' @@ -43,7 +43,7 @@ export function getTutorialIndex(id: string): number { export const TUTORIALS_CONFIG: Record
`
+- Use callbacks for custom navigation logic
+
+---
+
+## Progress Tracking System
+
+### Bitmask System
+
+Tutorials use a 64-bit bitmask where each bit represents one tutorial's completion status:
+
+```
+Bit 0: Tutorial with index 0 (unused, reserve)
+Bit 1: workspace-onboarding
+Bit 2: flow-live-tutorial
+Bit 3: troubleshoot-flow
+Bit 4: backgroundrunnables
+Bit 5: connection
+Bit 6: workspace-onboarding-operator
+...
+Bit 63: Maximum possible tutorial
+```
+
+### Key Functions (tutorialUtils.ts)
+
+```typescript
+// Mark tutorial as complete
+await updateProgress(tutorialIndex: number)
+
+// Sync progress from backend
+await syncTutorialsTodos()
+
+// Skip all tutorials
+await skipAllTodos()
+
+// Reset all progress
+await resetAllTodos()
+
+// Skip specific tutorials
+await skipTutorialsByIndexes(indexes: number[])
+
+// Complete specific tutorial
+await completeTutorialByIndex(index: number)
+```
+
+### Backend Integration
+
+**Table:** `tutorial_progress`
+```sql
+CREATE TABLE tutorial_progress (
+ email VARCHAR PRIMARY KEY,
+ progress BIT(64)
+);
+```
+
+**API Endpoint:** `POST /api/users/tutorial_progress`
+```typescript
+// Request body
+{
+ "index": 7, // Tutorial index to mark complete
+}
+```
+
+---
+
+## Role-Based Access
+
+### Available Roles
+
+```typescript
+type Role = 'admin' | 'developer' | 'operator'
+```
+
+### Role Hierarchy
+
+- **Admin**: Full access, can see all tutorials
+- **Developer**: Standard developer tutorials
+- **Operator**: Limited to operator-specific tutorials
+
+### Key Functions (roleUtils.ts)
+
+```typescript
+// Get current user's role
+const role = getUserEffectiveRole(user)
+
+// Check if user can access tutorial
+const canAccess = hasRoleAccess(userRole, tutorialRoles)
+```
+
+### Setting Role Requirements
+
+In `config.ts`:
+
+```typescript
+{
+ id: 'operator-only-tutorial',
+ roles: ['operator'], // Only operators see this
+ // ...
+}
+
+{
+ id: 'admin-dev-tutorial',
+ roles: ['admin', 'developer'], // Admins and developers see this
+ // ...
+}
+
+{
+ id: 'everyone-tutorial',
+ roles: ['admin', 'developer', 'operator'], // Everyone sees this
+ // ...
+}
+```
+
+---
+
+## Testing & Debugging
+
+### Testing Checklist
+
+- [ ] Tutorial appears in correct tab/category
+- [ ] Tutorial only visible to correct roles
+- [ ] Clicking tutorial navigates to correct URL with tutorial parameter
+- [ ] Tutorial auto-starts on page load with parameter
+- [ ] All steps highlight correct elements
+- [ ] Navigation controls work (prev/next)
+- [ ] Skip options work correctly
+- [ ] Completion marks tutorial as done in database
+- [ ] Banner updates to reflect completion
+- [ ] Tutorial doesn't auto-start after completion
+
+### Common Issues
+
+**Tutorial doesn't auto-start:**
+- Check URL parameter matches tutorial ID in config
+- Verify `onMount()` logic in page component
+- Ensure tutorial component is registered in router
+
+**Element not highlighting:**
+- Verify CSS selector is correct
+- Check if element exists when tutorial runs
+- Try using more specific selectors or IDs
+
+**Progress not saving:**
+- Check tutorial index is unique and correctly passed
+- Verify `updateProgress()` is called on final step
+- Check network tab for API call to `/api/users/tutorial_progress`
+- Inspect database `tutorial_progress` table
+
+**Wrong users see tutorial:**
+- Verify `roles` array in config
+- Check `getUserEffectiveRole()` returns correct role
+- Ensure role filtering logic in tutorial list component
+
+### Debugging Tools
+
+**Browser Console:**
+```javascript
+// Check current tutorials to do
+console.log($tutorialsToDo)
+
+// Check if tutorial is skipped
+console.log($skippedAll)
+
+// Get user role
+import { getUserEffectiveRole } from '$lib/tutorials/roleUtils'
+console.log(getUserEffectiveRole($workspaceStore?.operator, $userStore))
+```
+
+**Database Queries:**
+```sql
+-- Check user's tutorial progress
+SELECT email, progress::text FROM tutorial_progress WHERE email = 'user@example.com';
+
+-- Reset user's progress (testing)
+UPDATE tutorial_progress SET progress = B'0' WHERE email = 'user@example.com';
+
+-- See all tutorials and their completion
+SELECT
+ email,
+ (progress & (1::bit(64) << 1))::int AS workspace_onboarding,
+ (progress & (1::bit(64) << 2))::int AS flow_live_tutorial,
+ (progress & (1::bit(64) << 3))::int AS troubleshoot_flow
+FROM tutorial_progress;
+```
+
+---
+
+## Best Practices
+
+### Tutorial Design
+
+1. **Keep It Short**: 4-7 steps is ideal
+2. **Clear Objectives**: State what users will learn upfront
+3. **Highlight Key Elements**: Focus on essential features
+4. **Use Images**: Visual aids help comprehension
+5. **End with Encouragement**: Congratulate users on completion
+
+### Technical Best Practices
+
+1. **Unique Indexes**: Always use unique index numbers (1-64)
+2. **Stable Selectors**: Use IDs or specific classes for element highlighting
+3. **Error Handling**: Wrap `updateProgress()` in try-catch
+4. **Role Testing**: Test with all relevant user roles
+5. **Mobile Friendly**: Ensure tutorials work on different screen sizes
+
+### Code Organization
+
+1. **Group by Context**: Workspace, flow, app tutorials in separate folders
+2. **Consistent Naming**: `[Feature]Tutorial.svelte` convention
+3. **Reusable Steps**: Extract common step patterns to utilities
+4. **Document Complex Logic**: Add comments for non-obvious step behaviors
+
+---
+
+## Quick Reference
+
+### Creating a New Tutorial (Checklist)
+
+- [ ] Step 1: Add to `config.ts` with unique ID and index
+- [ ] Step 2: Create component in appropriate folder
+- [ ] Step 3: Register in tutorial router (WorkspaceTutorials, etc.)
+- [ ] Step 4: Add URL parameter handling in page component
+- [ ] Step 5: Test with appropriate user role
+- [ ] Step 6: Verify progress tracking in database
+
+### File Paths (Quick Copy)
+
+```
+# Config
+frontend/src/lib/tutorials/config.ts
+
+# Tutorial Containers
+frontend/src/lib/components/WorkspaceTutorials.svelte
+frontend/src/lib/components/FlowTutorials.svelte
+frontend/src/lib/components/AppTutorials.svelte
+
+# Tutorial Components
+frontend/src/lib/components/tutorials/Tutorial.svelte
+frontend/src/lib/components/tutorials/TutorialRouter.svelte
+frontend/src/lib/components/tutorials/workspace/[YourTutorial].svelte
+
+# Page Integration
+frontend/src/routes/(root)/(logged)/+page.svelte
+
+# Utilities
+frontend/src/lib/tutorialUtils.ts
+frontend/src/lib/tutorials/roleUtils.ts
+```
+
+---
+
+## Additional Resources
+
+- **Driver.js Documentation**: https://driverjs.com/docs/
+- **Svelte Tutorial System Examples**: See existing tutorials in `frontend/src/lib/components/tutorials/`
+- **Database Schema**: See `backend/summarized_schema.txt` for `tutorial_progress` table details