Skip to content

Commit dee4f4e

Browse files
authored
[FIX] Deleting an object from the details view keeps you on your current branch instead of redirecting to the main branch (#5948)
1 parent 10a8a26 commit dee4f4e

File tree

4 files changed

+114
-6
lines changed

4 files changed

+114
-6
lines changed

changelog/5232.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FIX: deleting an object from the details view keeps you on your current branch instead of redirecting to the main branch.

frontend/app/src/entities/nodes/object-item-details/action-buttons/details-buttons.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { ARTIFACT_DEFINITION_OBJECT, GENERIC_REPOSITORY_KIND } from "@/config/co
22
import { Generate } from "@/entities/artifacts/ui/generate";
33
import { GroupsManagerTriggerButton } from "@/entities/groups/ui/groups-manager-trigger-button";
44
import ObjectItemEditComponent from "@/entities/nodes/object-item-edit/object-item-edit-paginated";
5+
import { getObjectDetailsUrl2 } from "@/entities/nodes/utils";
6+
import { Permission } from "@/entities/permission/types";
57
import RepositoryActionMenu from "@/entities/repository/ui/repository-action-menu";
68
import { ModelSchema } from "@/entities/schema/types";
79
import { isGenericSchema } from "@/entities/schema/utils/is-generic-schema";
@@ -11,20 +13,17 @@ import SlideOver, { SlideOverTitle } from "@/shared/components/display/slide-ove
1113
import ModalDeleteObject from "@/shared/components/modals/modal-delete-object";
1214
import { Icon } from "@iconify-icon/react";
1315
import { useState } from "react";
14-
import { useLocation, useNavigate, useParams } from "react-router";
16+
import { useNavigate } from "react-router";
1517

1618
type DetailsButtonsProps = {
1719
schema: ModelSchema;
1820
objectDetailsData: any;
21+
permission: Permission;
1922
};
2023

2124
export function DetailsButtons({ schema, objectDetailsData, permission }: DetailsButtonsProps) {
22-
const location = useLocation();
23-
const { objectid } = useParams();
2425
const navigate = useNavigate();
2526

26-
const redirect = location.pathname.replace(objectid ?? "", "");
27-
2827
const [showEditModal, setShowEditModal] = useState(false);
2928
const [showDeleteModal, setShowDeleteModal] = useState(false);
3029

@@ -94,7 +93,7 @@ export function DetailsButtons({ schema, objectDetailsData, permission }: Detail
9493
rowToDelete={objectDetailsData}
9594
open={!!showDeleteModal}
9695
close={() => setShowDeleteModal(false)}
97-
onDelete={() => navigate(redirect)}
96+
onDelete={() => navigate(getObjectDetailsUrl2(schema.kind as string))}
9897
/>
9998
</>
10099
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { expect, test } from "@playwright/test";
2+
import { ACCOUNT_STATE_PATH } from "../../constants";
3+
import { createBranchAPI, deleteBranchAPI } from "../utils/graphql";
4+
const BRANCH_NAME = "object-details-delete";
5+
6+
test.describe("Object details - delete", () => {
7+
test.use({ storageState: ACCOUNT_STATE_PATH.ADMIN });
8+
9+
test.beforeAll(async ({ request }) => {
10+
await createBranchAPI(request, BRANCH_NAME);
11+
});
12+
13+
test.afterAll(async ({ request }) => {
14+
await deleteBranchAPI(request, BRANCH_NAME);
15+
});
16+
17+
test("delete an object and redirects to list view", async ({ page }) => {
18+
await page.goto(`/objects/BuiltinTag?branch=${BRANCH_NAME}`);
19+
await expect(page.getByTestId("branch-selector-trigger")).toContainText(
20+
"object-details-delete"
21+
);
22+
23+
await test.step("go to blue tag details", async () => {
24+
await page.getByRole("link", { name: "blue" }).click();
25+
});
26+
27+
await test.step("delete blue tag", async () => {
28+
await page.getByTestId("delete-button").click();
29+
await expect(page.getByTestId("modal-delete")).toContainText(
30+
'Are you sure you want to remove the Tag"blue"?'
31+
);
32+
await page.getByTestId("modal-delete-confirm").click();
33+
await expect(page.getByText("Object blue deleted")).toBeVisible();
34+
await expect(page.getByRole("link", { name: "blue" })).toBeHidden();
35+
});
36+
37+
await test.step("user is still on the same branch after delete", async () => {
38+
await expect(page.getByTestId("branch-selector-trigger")).toContainText(
39+
"object-details-delete"
40+
);
41+
});
42+
});
43+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { type APIRequestContext, expect } from "@playwright/test";
2+
3+
const API_URL = process.env.CI ? process.env.INFRAHUB_ADDRESS : "http://localhost:8000";
4+
const API_KEY = "06438eb2-8019-4776-878c-0941b1f1d1ec";
5+
6+
interface GraphQLResponse<T = any> {
7+
data?: T;
8+
errors?: Array<{ message: string }>;
9+
}
10+
11+
async function executeGraphQLMutation<T>(
12+
request: APIRequestContext,
13+
query: string,
14+
variables: Record<string, any>
15+
): Promise<T> {
16+
const response = await request.post(`${API_URL}/graphql`, {
17+
headers: { "X-INFRAHUB-KEY": API_KEY },
18+
data: { query, variables },
19+
});
20+
21+
expect(response.ok()).toBeTruthy();
22+
const result: GraphQLResponse<T> = await response.json();
23+
24+
if (result.errors) {
25+
result.errors.forEach((error) => {
26+
console.error(error.message);
27+
});
28+
throw new Error(`GraphQL Error: ${result.errors[0]?.message}`);
29+
}
30+
31+
return result.data as T;
32+
}
33+
34+
export const createBranchAPI = async (request: APIRequestContext, name: string) => {
35+
const mutation = `
36+
mutation BranchCreate($name: String!, $description: String, $sync_with_git: Boolean) {
37+
BranchCreate(data: { name: $name, description: $description, sync_with_git: $sync_with_git }) {
38+
object {
39+
id
40+
name
41+
description
42+
origin_branch
43+
branched_from
44+
created_at
45+
sync_with_git
46+
is_default
47+
}
48+
}
49+
}
50+
`;
51+
52+
return await executeGraphQLMutation(request, mutation, { name });
53+
};
54+
55+
export const deleteBranchAPI = async (request: APIRequestContext, name: string): Promise<any> => {
56+
const mutation = `
57+
mutation BranchDelete($name: String!) {
58+
BranchDelete(data: { name: $name }) {
59+
ok
60+
}
61+
}
62+
`;
63+
64+
return await executeGraphQLMutation(request, mutation, { name });
65+
};

0 commit comments

Comments
 (0)