From 0eff7450dbb86bcc6d6724c2c5167836ebae8e66 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Wed, 22 Jan 2025 16:05:26 +0530 Subject: [PATCH 1/4] fix: App card routing --- .../pages/Applications/ApplicationCard.tsx | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/app/client/src/pages/Applications/ApplicationCard.tsx b/app/client/src/pages/Applications/ApplicationCard.tsx index 484b7bb6eacf..7b34fb978955 100644 --- a/app/client/src/pages/Applications/ApplicationCard.tsx +++ b/app/client/src/pages/Applications/ApplicationCard.tsx @@ -477,26 +477,38 @@ export function ApplicationCard(props: ApplicationCardProps) { return viewerURL({ basePageId, params: viewerParams }); }, [props.application.defaultBasePageId, viewerParams]); - const launchApp = useCallback(() => { - setURLParams(); - dispatch(getCurrentUser()); - }, []); + const launchApp = useCallback( + (e) => { + e.preventDefault(); + e.stopPropagation(); + setURLParams(); + history.push(viewModeURL); + dispatch(getCurrentUser()); + }, + [dispatch, setURLParams, viewModeURL], + ); - const editApp = useCallback(() => { - setURLParams(); - dispatch(getCurrentUser()); - }, []); + const editApp = useCallback( + (e) => { + e.preventDefault(); + e.stopPropagation(); + setURLParams(); + history.push(editModeURL); + dispatch(getCurrentUser()); + }, + [dispatch, editModeURL, setURLParams], + ); - const launchMobileApp = useCallback(() => { - setURLParams(); - history.push( - viewerURL({ - basePageId: props.application.defaultBasePageId, - params: viewerParams, - }), - ); - dispatch(getCurrentUser()); - }, [dispatch, props.application.defaultBasePageId, viewerParams]); + const launchMobileApp = useCallback( + (e) => { + e.preventDefault(); + e.stopPropagation(); + setURLParams(); + history.push(viewModeURL); + dispatch(getCurrentUser()); + }, + [dispatch, props.application.defaultBasePageId, setURLParams, viewerParams], + ); return ( Date: Thu, 23 Jan 2025 14:30:26 +0530 Subject: [PATCH 2/4] chore: Allow for new tab open and other minor refactors --- .../pages/Applications/ApplicationCard.tsx | 104 +++++++++++------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/app/client/src/pages/Applications/ApplicationCard.tsx b/app/client/src/pages/Applications/ApplicationCard.tsx index 7b34fb978955..73629ee6e9a0 100644 --- a/app/client/src/pages/Applications/ApplicationCard.tsx +++ b/app/client/src/pages/Applications/ApplicationCard.tsx @@ -76,15 +76,18 @@ interface ApplicationCardProps { const IconScrollWrapper = styled.div` position: relative; + .t--icon-selected { background-color: var(--ads-v2-color-bg-muted); - border: var(--ads-v2-border-color); + border: var(--ads-v2-color-border); + svg { path { fill: var(--ads-v2-color-fg); } } } + svg { path { fill: var(--ads-v2-color-fg); @@ -98,13 +101,13 @@ export interface ModifiedMenuItemProps extends MenuItemProps { } export function ApplicationCard(props: ApplicationCardProps) { - const { isFetchingApplications } = props; + const { application, isFetchingApplications } = props; const theme = useContext(ThemeContext); const isSavingName = useSelector(getIsSavingAppName); const isErroredSavingName = useSelector(getIsErroredSavingAppName); const currentUser = useSelector(getCurrentUserSelector); const initialsAndColorCode = getInitialsAndColorCode( - props.application.name, + application.name, theme.colors.appCardColors, ); let initials = initialsAndColorCode[0]; @@ -120,9 +123,9 @@ export function ApplicationCard(props: ApplicationCardProps) { const [lastUpdatedValue, setLastUpdatedValue] = useState(""); const dispatch = useDispatch(); - const applicationId = props.application?.id; - const baseApplicationId = props.application?.baseId; - const showGitBadge = props.application?.gitApplicationMetadata?.branchName; + const applicationId = application.id; + const baseApplicationId = application.baseId; + const showGitBadge = application.gitApplicationMetadata?.branchName; const [editorParams, setEditorParams] = useState({}); const isGitPersistBranchEnabled = useFeatureFlag( FEATURE_FLAG.release_git_persist_branch_enabled, @@ -159,14 +162,14 @@ export function ApplicationCard(props: ApplicationCardProps) { useEffect(() => { let colorCode; - if (props.application.color) { - colorCode = props.application.color; + if (application.color) { + colorCode = application.color; } else { colorCode = getRandomPaletteColor(theme.colors.appCardColors); } setSelectedColor(colorCode); - }, [props.application.color]); + }, [application.color]); useEffect(() => { if (props.share) { @@ -205,22 +208,22 @@ export function ApplicationCard(props: ApplicationCardProps) { // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const appIcon = (props.application?.icon || + const appIcon = (application.icon || getApplicationIcon(applicationId)) as AppIconName; const hasEditPermission = isPermitted( - props.application?.userPermissions ?? [], + application.userPermissions ?? [], PERMISSION_TYPE.MANAGE_APPLICATION, ); const hasReadPermission = isPermitted( - props.application?.userPermissions ?? [], + application.userPermissions ?? [], PERMISSION_TYPE.READ_APPLICATION, ); const hasExportPermission = isPermitted( - props.application?.userPermissions ?? [], + application.userPermissions ?? [], PERMISSION_TYPE.EXPORT_APPLICATION, ); const hasDeletePermission = hasDeleteApplicationPermission( - props.application?.userPermissions, + application.userPermissions, ); const updateColor = (color: string) => { @@ -247,7 +250,7 @@ export function ApplicationCard(props: ApplicationCardProps) { existingLink && existingLink.remove(); const link = document.createElement("a"); - const branchName = props.application.gitApplicationMetadata?.branchName; + const branchName = application.gitApplicationMetadata?.branchName; link.href = getExportAppAPIRoute(applicationId, branchName); link.id = id; @@ -259,7 +262,7 @@ export function ApplicationCard(props: ApplicationCardProps) { } setIsMenuOpen(false); - toast.show(`Successfully exported ${props.application.name}`, { + toast.show(`Successfully exported ${application.name}`, { kind: "success", }); }; @@ -307,8 +310,8 @@ export function ApplicationCard(props: ApplicationCardProps) { } }; - if (initials.length < 2 && props.application.name.length > 1) { - initials += props.application.name[1].toUpperCase() || ""; + if (initials.length < 2 && application.name.length > 1) { + initials += application.name[1].toUpperCase() || ""; } const handleMenuOnClose = (open: boolean) => { @@ -317,7 +320,7 @@ export function ApplicationCard(props: ApplicationCardProps) { setShowOverlay(false); addDeleteOption(); - if (lastUpdatedValue && props.application.name !== lastUpdatedValue) { + if (lastUpdatedValue && application.name !== lastUpdatedValue) { props.update && props.update(applicationId, { name: lastUpdatedValue, @@ -353,7 +356,7 @@ export function ApplicationCard(props: ApplicationCardProps) { > page.id === props.application.defaultPageId, - ); + const setURLParams = useCallback(() => { + const page: ApplicationPagePayload | undefined = application.pages.find( + (page) => page.id === application.defaultPageId, + ); if (!page) return; urlBuilder.updateURLParams( { - applicationSlug: props.application.slug, - applicationVersion: props.application.applicationVersion, - baseApplicationId: props.application.baseId, + applicationSlug: application.slug, + applicationVersion: application.applicationVersion, + baseApplicationId: application.baseId, }, - props.application.pages.map((page) => ({ + application.pages.map((page) => ({ pageSlug: page.slug, customSlug: page.customSlug, basePageId: page.baseId, })), ); - } + }, [ + application.applicationVersion, + application.baseId, + application.defaultPageId, + application.pages, + application.slug, + ]); const editModeURL = useMemo(() => { - const basePageId = props.application.defaultBasePageId; + const basePageId = application.defaultBasePageId; if (!basePageId) return ""; return builderURL({ basePageId, params: editorParams }); - }, [props.application.defaultBasePageId, editorParams]); + }, [application.defaultBasePageId, editorParams]); const viewModeURL = useMemo(() => { - const basePageId = props.application.defaultBasePageId; + const basePageId = application.defaultBasePageId; if (!basePageId) return ""; return viewerURL({ basePageId, params: viewerParams }); - }, [props.application.defaultBasePageId, viewerParams]); + }, [application.defaultBasePageId, viewerParams]); const launchApp = useCallback( - (e) => { + (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); + + if (e.ctrlKey || e.metaKey) { + window.open(viewModeURL, "_blank"); + + return; + } + setURLParams(); history.push(viewModeURL); dispatch(getCurrentUser()); @@ -489,9 +504,16 @@ export function ApplicationCard(props: ApplicationCardProps) { ); const editApp = useCallback( - (e) => { + (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); + + if (e.ctrlKey || e.metaKey) { + window.open(editModeURL, "_blank"); + + return; + } + setURLParams(); history.push(editModeURL); dispatch(getCurrentUser()); @@ -507,7 +529,7 @@ export function ApplicationCard(props: ApplicationCardProps) { history.push(viewModeURL); dispatch(getCurrentUser()); }, - [dispatch, props.application.defaultBasePageId, setURLParams, viewerParams], + [setURLParams, viewModeURL, dispatch], ); return ( @@ -526,8 +548,8 @@ export function ApplicationCard(props: ApplicationCardProps) { setShowOverlay={setShowOverlay} showGitBadge={Boolean(showGitBadge)} showOverlay={showOverlay} - testId={`t--application-card ${props.application.name}`} - title={props.application.name} + testId={`t--application-card ${application.name}`} + title={application.name} titleTestId="t--app-card-name" > {hasEditPermission && !isMenuOpen && ( From 4c2484ec96dc3452942099340b117d25a2abefac Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Fri, 24 Jan 2025 13:41:20 +0530 Subject: [PATCH 3/4] chore: Add locator changes --- app/client/cypress/support/Pages/HomePage.ts | 11 ++++++++++- app/client/cypress/support/WorkspaceCommands.js | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/client/cypress/support/Pages/HomePage.ts b/app/client/cypress/support/Pages/HomePage.ts index b231b0f12dd1..bedf54eb3e56 100644 --- a/app/client/cypress/support/Pages/HomePage.ts +++ b/app/client/cypress/support/Pages/HomePage.ts @@ -3,6 +3,7 @@ import HomePageLocators from "../../locators/HomePage"; import SignupPageLocators from "../../locators/SignupPage.json"; import { ObjectsRegistry } from "../Objects/Registry"; import { AppSidebar, PageLeftPane } from "./EditorNavigation"; + export class HomePage { private agHelper = ObjectsRegistry.AggregateHelper; private locator = ObjectsRegistry.CommonLocators; @@ -131,6 +132,7 @@ export class HomePage { private _membersTab = "[data-testid=t--tab-members]"; public _searchWorkspaceLocator = (workspaceName: string) => `[data-testid="${workspaceName}"]`; + public SwitchToAppsTab() { this.agHelper.GetNClick(this._homeTab); } @@ -323,7 +325,7 @@ export class HomePage { .click({ force: true }); this.agHelper.GetNClick(this._newButtonCreateApplication); this.AssertApplicationCreated(); - this.agHelper.AssertElementVisibility(this.locator._sidebar); + this.agHelper.AssertElementVisibility(this._editorSidebar); this.agHelper.AssertElementAbsence(this.locator._loading); if (appname) this.RenameApplication(appname); } @@ -797,6 +799,7 @@ export class HomePage { } }); } + public SelectWorkspace(workspaceName: string, networkCallAlias = true) { this.agHelper .GetElement(this._leftPanel) @@ -805,4 +808,10 @@ export class HomePage { networkCallAlias && this.assertHelper.AssertNetworkStatus("@getApplicationsOfWorkspace"); } + + public SelectAppToEdit(index: number = 0) { + cy.get(HomePageLocators.applicationCard).eq(index).trigger("mouseover"); + cy.get(HomePageLocators.appEditIcon).click(); + this.agHelper.AssertElementVisibility(this._editorSidebar); + } } diff --git a/app/client/cypress/support/WorkspaceCommands.js b/app/client/cypress/support/WorkspaceCommands.js index 2b70d168d95b..b329bce1f011 100644 --- a/app/client/cypress/support/WorkspaceCommands.js +++ b/app/client/cypress/support/WorkspaceCommands.js @@ -12,6 +12,7 @@ import { ObjectsRegistry } from "../support/Objects/Registry"; const agHelper = ObjectsRegistry.AggregateHelper; const assertHelper = ObjectsRegistry.AssertHelper; const homePageTS = ObjectsRegistry.HomePage; +const appSettings = ObjectsRegistry.AppSettings; export const initLocalstorage = () => { cy.window().then((window) => { @@ -62,6 +63,7 @@ Cypress.Commands.add("launchApp", () => { "response.body.responseMeta.status", 200, ); + agHelper.AssertElementVisibility(appSettings.locators._applicationName); }); Cypress.Commands.add("AppSetupForRename", () => { From daf90eb96bd16dd84e3eccadd2ba50a764841df3 Mon Sep 17 00:00:00 2001 From: Hetu Nandu Date: Mon, 27 Jan 2025 12:57:50 +0530 Subject: [PATCH 4/4] chore: Remove href from local nav elements --- .../pages/Applications/ApplicationCard.tsx | 23 ++++--------------- app/client/src/pages/Editor/AppsmithLink.tsx | 10 ++++++-- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/app/client/src/pages/Applications/ApplicationCard.tsx b/app/client/src/pages/Applications/ApplicationCard.tsx index 73629ee6e9a0..4e0bcd81df08 100644 --- a/app/client/src/pages/Applications/ApplicationCard.tsx +++ b/app/client/src/pages/Applications/ApplicationCard.tsx @@ -487,9 +487,6 @@ export function ApplicationCard(props: ApplicationCardProps) { const launchApp = useCallback( (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - if (e.ctrlKey || e.metaKey) { window.open(viewModeURL, "_blank"); @@ -505,9 +502,6 @@ export function ApplicationCard(props: ApplicationCardProps) { const editApp = useCallback( (e: React.MouseEvent) => { - e.preventDefault(); - e.stopPropagation(); - if (e.ctrlKey || e.metaKey) { window.open(editModeURL, "_blank"); @@ -521,16 +515,11 @@ export function ApplicationCard(props: ApplicationCardProps) { [dispatch, editModeURL, setURLParams], ); - const launchMobileApp = useCallback( - (e) => { - e.preventDefault(); - e.stopPropagation(); - setURLParams(); - history.push(viewModeURL); - dispatch(getCurrentUser()); - }, - [setURLParams, viewModeURL, dispatch], - ); + const launchMobileApp = useCallback(() => { + setURLParams(); + history.push(viewModeURL); + dispatch(getCurrentUser()); + }, [setURLParams, viewModeURL, dispatch]); return ( { // we are removing non input related props before passing them in the components @@ -14,6 +15,7 @@ export const StyledLink = styled((props) => { min-width: 24px; width: 24px; display: inline-block; + img { min-width: 24px; width: 24px; @@ -22,9 +24,13 @@ export const StyledLink = styled((props) => { `; export const AppsmithLink = () => { + const handleOnClick = useCallback(() => { + history.push(APPLICATIONS_URL); + }, []); + return ( - +