feat: add observable UX for community interaction tracking (#7512)

* ✨ (model.py): add UserOptin class to manage user opt-in actions for better organization and extensibility
♻️ (model.py): refactor User model to include user_optin field as a dictionary to store opt-in actions for users

* [autofix.ci] apply automated fixes

* change name optins

* [autofix.ci] apply automated fixes

* ✨ (add_optins_column_to_user.py): Add optins column to the user table to store user preferences
♻️ (model.py): Refactor UserOptin class to BaseModel for better type hinting and add optins field to User model with default values and proper typing

* [autofix.ci] apply automated fixes

* 🐛 (add_optins_column_to_user.py): fix an issue where the optins column was not being added if it already existed in the user table

* ✨ (empty-page.tsx): Add new page EmptyPageCommunity to display community information and actions
✨ (main-page.tsx): Add new page CollectionPage to manage collections and folders
🔧 (routes.tsx): Update import path for CollectionPage to point to the new main-page file

* ✨ (background-gradient.tsx): Add a new component BackgroundGradient to create a visually appealing background gradient effect for UI elements
📝 (empty-page.tsx): Refactor EmptyPageCommunity component to use the newly added BackgroundGradient component for GitHub and Discord sections to enhance visual appeal and consistency

* 📝 (tasks.mdc): Add concise task management protocol for sequential mode to improve task organization and execution
✨ (frontend): Introduce DotBackgroundDemo component for creating a visually appealing dot background effect
♻️ (frontend): Refactor BackgroundGradient component to improve gradient styling and border consistency
🔧 (frontend): Update motion import in background-gradient.tsx to use framer-motion instead of motion/react
🔧 (icons): Add missing newline at the end of Anthropic icon file
🔧 (empty-page.tsx): Adjust styling classes and z-index to improve layout and visual hierarchy in EmptyPageCommunity component

* ✨ (empty-page.tsx): add githubBg image import to use as background image for GitHub link
♻️ (empty-page.tsx): refactor positioning and styling of GitHub link elements for better alignment and readability

* 🔧 refactor(server.ts): change port variable case from lowercase port to uppercase PORT to improve semantics
✨ refactor(server.ts): add support for process.env.PORT environment variable to be able to run app on a configurable port

* 📝 (AccountMenu/index.tsx): Update imports and remove unused code for better organization and performance
🔧 (use-get-version.ts): Add functionality to refresh the latest version in darkStore after fetching version data
♻️ (darkStore.ts): Add refreshLatestVersion function to update the latest version in darkStore
📝 (dark/index.ts): Add latestVersion field and refreshLatestVersion function to DarkStoreType for better state management

* ✨ (AccountMenu/index.tsx): Add constants for Discord, Docs, GitHub, and Twitter URLs for better maintainability and reusability
📝 (constants.ts): Update Twitter URL to a new value for consistency with other URLs
📝 (TwitterX): Add new TwitterX icon and component for use in the application
📝 (styleUtils.ts): Import and use the new TwitterXIcon in the list of node icons
📝 (utils.ts): Update formatNumber function to handle undefined input values for better error handling

* [autofix.ci] apply automated fixes

* 📝 (add_optins_column_to_user.py): Update down_revision to '1b8b740a6fa3' for consistency
🔧 (AccountMenu/index.tsx): Adjust classNameSize prop value to 'w-[272px]' for styling consistency
🔧 (HeaderMenu/index.tsx): Update HeaderMenuItems component to accept classNameSize prop for dynamic styling
🔧 (langflow-counts.tsx): Adjust styling for better visual consistency and spacing
🔧 (index.tsx): Update className for Bell icon to include text-muted-foreground and strokeWidth
🔧 (get-started-progress.tsx): Update styling and spacing for better visual consistency
🔧 (header-buttons.tsx): Add Separator component for visual separation in HeaderButtons component

* 🔧 (AccountMenu/index.tsx): Adjust padding in AccountMenu component for better alignment and spacing. Fix ThemeButtons positioning for improved layout.

* ✨ (appHeaderComponent/index.tsx): Add support for managing flows and folders in the app header component
📝 (get-started-progress.tsx): Update heading tag to improve semantics
📝 (empty-page.tsx): Update text content in empty page to provide clearer instructions and information

* ✨ (background-gradient.tsx): Add support for dynamic border radius in BackgroundGradient component
🔧 (empty-page.tsx): Remove BackgroundGradient import and replace it with EnhancedBeamEffect component
🔧 (empty-page.tsx): Update styles and classes for EnhancedBeamEffect component and adjust layout
✨ (enchanced-beam-effect.tsx): Create EnhancedBeamEffect component to add enhanced beam effect to UI components

* ✨ (frontend): update text content and button labels in empty page component for better user experience
📝 (frontend): add data-testid attributes for testing purposes in various components
🔧 (frontend): add new test file for user progress tracking feature with Playwright tests

* ✨ (AccountMenu/index.tsx): Add Admin Page button for admin users in the account menu component
🔧 (user-progress-track.spec.ts): Add utility function addNewUserAndLogin to facilitate adding and logging in new users for testing purposes

* [autofix.ci] apply automated fixes

* 🐛 (get-started-progress.tsx): fix calculation of percentage to ensure it does not exceed 100%

* ✨ (empty-page.tsx): Add Lucide ExternalLink component for external links and update styling for external link icons
♻️ (empty-page.tsx): Refactor CSS classes for external link icons to improve readability and maintainability
📝 (index.css): Add custom CSS variable for Discord color
📝 (tailwind.config.mjs): Add Discord color to Tailwind CSS custom colors

* [autofix.ci] apply automated fixes

* add logo png

* ✨ (index.tsx): Add z-50 class to improve stacking context in CardsWrapComponent
✨ (empty-page.tsx): Add text-center class to center text elements in EmptyPageCommunity
✨ (empty-page.tsx): Adjust spacing and alignment in EmptyPageCommunity for better layout and readability

* 🐛 (AccountMenu/index.tsx): fix condition to show admin options only when isAdmin is true and autoLogin is false

* 🔧 (alertDropDown/index.tsx): update z-index value in PopoverContent class to z-50 for proper stacking order

* 🔧 (index.tsx): update z-index value to improve the stacking order of the component on the page

* ♻️ (index.tsx): refactor classNames in CardsWrapComponent to improve readability and maintainability

* 🐛 (empty-page.tsx): fix data-testid attribute value to match the updated element name for better consistency and clarity
🐛 (user-progress-track.spec.ts): fix test cases to match the updated data-testid attribute value for the main page title element to ensure accurate testing and assertions

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Cristhian Zanforlin Lousa 2025-04-22 20:26:33 -03:00 • committed by GitHub
commit a8ae17b86d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 1482 additions and 209 deletions

View file

@ -0,0 +1,242 @@
import { expect, test } from "@playwright/test";
import { DISCORD_URL, GITHUB_URL } from "../../../src/constants/constants";
import { addNewUserAndLogin } from "../../utils/add-new-user-and-loggin";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
test(
"admin user must be able to track their progress in getting started",
{ tag: ["@release", "@api"] },
async ({ page, context }) => {
await page.goto("/");
// Wait for any loading text to disappear
await page.waitForSelector('text="Loading"', {
state: "hidden",
timeout: 30000,
});
await page.waitForTimeout(2000);
let emptyButton = page.getByTestId("new_project_btn_empty_page");
while ((await emptyButton.count()) === 0) {
await page.getByTestId("home-dropdown-menu").first().click();
await page.getByTestId("btn_delete_dropdown_menu").first().click();
await page
.getByTestId("btn_delete_delete_confirmation_modal")
.first()
.click();
await page.waitForTimeout(1000);
emptyButton = page.getByTestId("new_project_btn_empty_page");
}
await expect(emptyButton).toBeVisible();
await expect(page.getByTestId("mainpage_title")).toBeVisible();
await expect(page.getByTestId("empty_page_description")).toBeVisible();
await expect(page.getByTestId("empty_page_github_button")).toBeVisible();
await expect(page.getByTestId("empty_page_discord_button")).toBeVisible();
await expect(
page.getByTestId("empty_page_drag_and_drop_text"),
).toBeVisible();
await expect(page.getByTestId("app-header")).not.toBeVisible();
await page.getByTestId("empty_page_github_button").click();
const pagePromiseGithub = context.waitForEvent("page");
const newPageGithub = await pagePromiseGithub;
await newPageGithub.waitForTimeout(3000);
const newUrlGithub = newPageGithub.url();
await expect(newUrlGithub).toContain(GITHUB_URL);
await newPageGithub.close();
await expect(page.getByTestId("mainpage_title")).toBeVisible();
await expect(page.getByTestId("empty_page_description")).toBeVisible();
await page.getByTestId("new_project_btn_empty_page").click();
await page.getByTestId("side_nav_options_all-templates").click();
await page.getByRole("heading", { name: "Basic Prompting" }).click();
await page.waitForSelector('[data-testid="icon-ChevronLeft"]', {
timeout: 100000,
});
await page.getByTestId("icon-ChevronLeft").first().click();
await page.waitForSelector('[data-testid="home-dropdown-menu"]', {
timeout: 100000,
});
await expect(page.getByTestId("app-header")).toBeVisible();
await expect(
page.getByTestId("github_starred_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("create_flow_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("discord_joined_icon_get_started"),
).not.toBeVisible();
await expect(
page.getByTestId("get_started_progress_percentage").first(),
).toHaveText("66%");
await page.getByTestId("discord_joined_btn_get_started").click();
const pagePromiseDiscord = context.waitForEvent("page");
const newPageDiscord = await pagePromiseDiscord;
await newPageDiscord.waitForTimeout(3000);
const newUrlDiscord = newPageDiscord.url();
await expect(newUrlDiscord).toContain(DISCORD_URL);
await newPageDiscord.close();
await expect(page.getByTestId("app-header")).toBeVisible();
await expect(
page.getByTestId("discord_joined_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("create_flow_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("github_starred_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("get_started_progress_percentage").first(),
).toHaveText("100%");
await page.getByTestId("close_get_started_dialog").click();
await expect(
page.getByTestId("discord_joined_icon_get_started"),
).not.toBeVisible();
await expect(
page.getByTestId("create_flow_icon_get_started"),
).not.toBeVisible();
await expect(
page.getByTestId("github_starred_icon_get_started"),
).not.toBeVisible();
},
);
test(
"normal user must be able to track their progress in getting started",
{ tag: ["@release", "@api"] },
async ({ page, context }) => {
await addNewUserAndLogin(page);
// Wait for any loading text to disappear
await page.waitForSelector('text="Loading"', {
state: "hidden",
timeout: 30000,
});
await page.waitForTimeout(2000);
let emptyButton = page.getByTestId("new_project_btn_empty_page");
while ((await emptyButton.count()) === 0) {
await page.getByTestId("home-dropdown-menu").first().click();
await page.getByTestId("btn_delete_dropdown_menu").first().click();
await page
.getByTestId("btn_delete_delete_confirmation_modal")
.first()
.click();
await page.waitForTimeout(1000);
emptyButton = page.getByTestId("new_project_btn_empty_page");
}
await expect(emptyButton).toBeVisible();
await expect(page.getByTestId("mainpage_title")).toBeVisible();
await expect(page.getByTestId("empty_page_description")).toBeVisible();
await expect(page.getByTestId("empty_page_github_button")).toBeVisible();
await expect(page.getByTestId("empty_page_discord_button")).toBeVisible();
await expect(
page.getByTestId("empty_page_drag_and_drop_text"),
).toBeVisible();
await expect(page.getByTestId("app-header")).not.toBeVisible();
await page.getByTestId("empty_page_github_button").click();
const pagePromiseGithub = context.waitForEvent("page");
const newPageGithub = await pagePromiseGithub;
await newPageGithub.waitForTimeout(3000);
const newUrlGithub = newPageGithub.url();
await expect(newUrlGithub).toContain(GITHUB_URL);
await newPageGithub.close();
await expect(page.getByTestId("mainpage_title")).toBeVisible();
await expect(page.getByTestId("empty_page_description")).toBeVisible();
await page.getByTestId("new_project_btn_empty_page").click();
await page.getByTestId("side_nav_options_all-templates").click();
await page.getByRole("heading", { name: "Basic Prompting" }).click();
await page.waitForSelector('[data-testid="icon-ChevronLeft"]', {
timeout: 100000,
});
await page.getByTestId("icon-ChevronLeft").first().click();
await page.waitForSelector('[data-testid="home-dropdown-menu"]', {
timeout: 100000,
});
await expect(page.getByTestId("app-header")).toBeVisible();
await expect(
page.getByTestId("github_starred_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("create_flow_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("discord_joined_icon_get_started"),
).not.toBeVisible();
await expect(
page.getByTestId("get_started_progress_percentage").first(),
).toHaveText("66%");
await page.getByTestId("discord_joined_btn_get_started").click();
const pagePromiseDiscord = context.waitForEvent("page");
const newPageDiscord = await pagePromiseDiscord;
await newPageDiscord.waitForTimeout(3000);
const newUrlDiscord = newPageDiscord.url();
await expect(newUrlDiscord).toContain(DISCORD_URL);
await newPageDiscord.close();
await expect(page.getByTestId("app-header")).toBeVisible();
await expect(
page.getByTestId("discord_joined_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("create_flow_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("github_starred_icon_get_started"),
).toBeVisible();
await expect(
page.getByTestId("get_started_progress_percentage").first(),
).toHaveText("100%");
await page.getByTestId("close_get_started_dialog").click();
await expect(
page.getByTestId("discord_joined_icon_get_started"),
).not.toBeVisible();
await expect(
page.getByTestId("create_flow_icon_get_started"),
).not.toBeVisible();
await expect(
page.getByTestId("github_starred_icon_get_started"),
).not.toBeVisible();
},
);