Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: App card routing #38798

Merged
merged 5 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion app/client/cypress/support/Pages/HomePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -797,6 +799,7 @@ export class HomePage {
}
});
}

public SelectWorkspace(workspaceName: string, networkCallAlias = true) {
this.agHelper
.GetElement(this._leftPanel)
Expand All @@ -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);
}
}
2 changes: 2 additions & 0 deletions app/client/cypress/support/WorkspaceCommands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -62,6 +63,7 @@ Cypress.Commands.add("launchApp", () => {
"response.body.responseMeta.status",
200,
);
agHelper.AssertElementVisibility(appSettings.locators._applicationName);
});

Cypress.Commands.add("AppSetupForRename", () => {
Expand Down
131 changes: 76 additions & 55 deletions app/client/src/pages/Applications/ApplicationCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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];
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) => {
Expand All @@ -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;
Expand All @@ -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",
});
};
Expand Down Expand Up @@ -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) => {
Expand All @@ -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,
Expand Down Expand Up @@ -353,7 +356,7 @@ export function ApplicationCard(props: ApplicationCardProps) {
>
<EditableText
className="px-3 pt-2 pb-2 t--application-name"
defaultValue={props.application.name}
defaultValue={application.name}
editInteractionKind={EditInteractionKind.SINGLE}
fill
hideEditIcon={false}
Expand Down Expand Up @@ -435,68 +438,88 @@ export function ApplicationCard(props: ApplicationCardProps) {
);

const editedByText = generateEditedByText({
modifiedAt: props.application.modifiedAt,
modifiedBy: props.application.modifiedBy,
modifiedAt: application.modifiedAt,
modifiedBy: application.modifiedBy,
});

function setURLParams() {
const page: ApplicationPagePayload | undefined =
props.application.pages.find(
(page) => 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(() => {
setURLParams();
dispatch(getCurrentUser());
}, []);
const launchApp = useCallback(
(e: React.MouseEvent) => {
if (e.ctrlKey || e.metaKey) {
window.open(viewModeURL, "_blank");

const editApp = useCallback(() => {
setURLParams();
dispatch(getCurrentUser());
}, []);
return;
}

setURLParams();
history.push(viewModeURL);
dispatch(getCurrentUser());
},
[dispatch, setURLParams, viewModeURL],
);

const editApp = useCallback(
(e: React.MouseEvent) => {
if (e.ctrlKey || e.metaKey) {
window.open(editModeURL, "_blank");

return;
}

setURLParams();
history.push(editModeURL);
dispatch(getCurrentUser());
},
[dispatch, editModeURL, setURLParams],
);

const launchMobileApp = useCallback(() => {
setURLParams();
history.push(
viewerURL({
basePageId: props.application.defaultBasePageId,
params: viewerParams,
}),
);
history.push(viewModeURL);
dispatch(getCurrentUser());
}, [dispatch, props.application.defaultBasePageId, viewerParams]);
}, [setURLParams, viewModeURL, dispatch]);

return (
<Card
Expand All @@ -514,14 +537,13 @@ 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 && (
<Button
className="t--application-edit-link"
href={editModeURL}
onClick={editApp}
renderAs="a"
size="md"
Expand All @@ -533,7 +555,6 @@ export function ApplicationCard(props: ApplicationCardProps) {
{!isMenuOpen && (
<Button
className="t--application-view-link"
href={viewModeURL}
kind="secondary"
onClick={launchApp}
renderAs="a"
Expand Down
10 changes: 8 additions & 2 deletions app/client/src/pages/Editor/AppsmithLink.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from "react";
import React, { useCallback } from "react";
import { Link, Tooltip } from "@appsmith/ads";
import styled from "styled-components";
import { LOGO_TOOLTIP, createMessage } from "ee/constants/messages";
import { APPLICATIONS_URL } from "constants/routes";
import AppsmithLogo from "assets/images/appsmith_logo_square.png";
import history from "utils/history";

export const StyledLink = styled((props) => {
// we are removing non input related props before passing them in the components
Expand All @@ -14,6 +15,7 @@ export const StyledLink = styled((props) => {
min-width: 24px;
width: 24px;
display: inline-block;

img {
min-width: 24px;
width: 24px;
Expand All @@ -22,9 +24,13 @@ export const StyledLink = styled((props) => {
`;

export const AppsmithLink = () => {
const handleOnClick = useCallback(() => {
history.push(APPLICATIONS_URL);
}, []);

return (
<Tooltip content={createMessage(LOGO_TOOLTIP)} placement="bottomLeft">
<StyledLink target="_self" to={APPLICATIONS_URL}>
<StyledLink onClick={handleOnClick}>
<img
alt="Appsmith logo"
className="t--appsmith-logo"
Expand Down
Loading