diff --git a/.env.example b/.env.example
index 6b78d3253..0f46c1b49 100644
--- a/.env.example
+++ b/.env.example
@@ -19,6 +19,7 @@ SPONSOR_USERS_SCOPES="show-medata/read show-medata/write access-requests/read ac
EMAIL_SCOPES="clients/read templates/read templates/write emails/read"
FILE_UPLOAD_SCOPES="files/upload"
FILE_UPLOAD_ALLOWED_EXTENSIONS="pdf,jpg,jpeg,png,ppt,key,pptx"
+FILE_UPLOAD_USE_V4=
SPONSOR_PAGES_API_URL=https://sponsor-pages-api.dev.fnopen.com
SPONSOR_REPORTS_API_URL=https://sponsor-reports-api.dev.fnopen.com
SPONSOR_PAGES_SCOPES="page-template/read page-template/write show-page/read show-page/write media-upload/read"
diff --git a/package.json b/package.json
index 53f73d565..ba894aed3 100644
--- a/package.json
+++ b/package.json
@@ -55,6 +55,8 @@
"@uiw/codemirror-theme-sublime": "^4.21.23",
"@uiw/react-codemirror": "^4.21.7",
"@uiw/react-color-sketch": "^2.1.0",
+ "@uppy/aws-s3": "^5.1.0",
+ "@uppy/core": "^5.2.0",
"ably": "^2.30.0",
"address-rfc2822": "^2.2.2",
"awesome-bootstrap-checkbox": "^1.0.1",
@@ -95,7 +97,7 @@
"moment-duration-format": "^2.3.2",
"moment-timezone": "^0.5.33",
"mui-color-input": "^9.0.0",
- "openstack-uicore-foundation": "5.0.73-beta.1",
+ "openstack-uicore-foundation": "5.0.75",
"p-limit": "^6.1.0",
"path-browserify": "^1.0.1",
"postcss-loader": "^6.2.1",
diff --git a/src/app.js b/src/app.js
index 7a8fa36b1..55da85ca2 100644
--- a/src/app.js
+++ b/src/app.js
@@ -86,6 +86,7 @@ window.SPONSOR_USERS_API_URL = process.env.SPONSOR_USERS_API_URL;
window.SPONSOR_PAGES_API_URL = process.env.SPONSOR_PAGES_API_URL;
window.SPONSOR_REPORTS_API_URL = process.env.SPONSOR_REPORTS_API_URL;
window.FILE_UPLOAD_API_BASE_URL = process.env.FILE_UPLOAD_API_BASE_URL;
+window.FILE_UPLOAD_USE_V4 = process.env.FILE_UPLOAD_USE_V4;
window.SIGNAGE_BASE_URL = process.env.SIGNAGE_BASE_URL;
window.INVENTORY_API_BASE_URL = process.env.INVENTORY_API_BASE_URL;
window.OAUTH2_CLIENT_ID = process.env.OAUTH2_CLIENT_ID;
diff --git a/src/components/forms/__tests__/company-form.test.js b/src/components/forms/__tests__/company-form.test.js
index ed1dcc90d..55a9e75b2 100644
--- a/src/components/forms/__tests__/company-form.test.js
+++ b/src/components/forms/__tests__/company-form.test.js
@@ -15,28 +15,50 @@ jest.mock("openstack-uicore-foundation/lib/utils/query-actions", () => ({
})
}));
+function mockUploadInput({
+ id,
+ onUploadComplete,
+ onUploadStart,
+ onRemove,
+ value
+}) {
+ return (
+
+
+
+
+ );
+}
+
jest.mock(
"openstack-uicore-foundation/lib/components/inputs/upload-input-v3",
- () => ({
- __esModule: true,
- default: ({ id, onUploadComplete, onUploadStart, value }) => (
-
-
-
- )
- })
+ () => ({ __esModule: true, default: mockUploadInput })
+);
+
+jest.mock(
+ "openstack-uicore-foundation/lib/components/inputs/upload-input-v4",
+ () => ({ __esModule: true, default: mockUploadInput })
);
jest.mock(
@@ -160,6 +182,7 @@ const Harness = ({
onDeleteSponsorship={onDeleteSponsorship}
/>
{JSON.stringify(formik.values)}
+ {String(isSaving)}
);
};
@@ -252,6 +275,25 @@ describe("CompanyForm", () => {
expect(onAttach).not.toHaveBeenCalled();
});
+ it("clears the saving state when a new company cancels an in-flight V4 upload", async () => {
+ const user = userEvent.setup();
+ const onRemove = jest.fn(() => Promise.resolve());
+ window.FILE_UPLOAD_USE_V4 = "true";
+
+ try {
+ render();
+
+ await act(async () => {
+ await user.click(screen.getByTestId("cancel-upload-logo"));
+ });
+
+ expect(screen.getByTestId("debug-saving")).toHaveTextContent("false");
+ expect(onRemove).not.toHaveBeenCalled();
+ } finally {
+ delete window.FILE_UPLOAD_USE_V4;
+ }
+ });
+
it("reverts the logo preview when onAttach fails for an existing company", async () => {
const user = userEvent.setup();
let rejectAttach;
diff --git a/src/components/forms/badge-feature-type-form.js b/src/components/forms/badge-feature-type-form.js
index 40aef9d7f..3a47aa83a 100644
--- a/src/components/forms/badge-feature-type-form.js
+++ b/src/components/forms/badge-feature-type-form.js
@@ -18,7 +18,7 @@ import { useFormikContext } from "formik";
import { Box, Grid2, InputLabel } from "@mui/material";
import MuiFormikTextField from "openstack-uicore-foundation/lib/components/mui/formik-inputs/textfield";
import FormikTextEditor from "openstack-uicore-foundation/lib/components/mui/formik-inputs/texteditor";
-import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3";
+import FileUploadInput from "../inputs/file-upload-input";
import useScrollToError from "../../hooks/useScrollToError";
import { KB, MAX_BADGE_FEATURE_IMAGE_UPLOAD_SIZE } from "../../utils/constants";
@@ -101,7 +101,7 @@ const BadgeFeatureTypeForm = ({ entity, onRemoveImage, onUploadingChange }) => {
{T.translate("edit_badge_feature.image")}
- {
onUploadStart={() => onUploadingChange(true)}
onError={() => onUploadingChange(false)}
onRemove={handleRemoveImage}
- postUrl={`${window.FILE_UPLOAD_API_BASE_URL}/api/v1/files/upload`}
- djsConfig={{ withCredentials: true }}
maxFiles={1}
canAdd={!formik.values.image}
mediaType={{
diff --git a/src/components/forms/company-form.js b/src/components/forms/company-form.js
index 5b216b71d..66332a9ef 100644
--- a/src/components/forms/company-form.js
+++ b/src/components/forms/company-form.js
@@ -23,11 +23,11 @@ import {
MenuItem,
Select
} from "@mui/material";
-import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3";
import { getCountryList } from "openstack-uicore-foundation/lib/utils/query-actions";
import Table from "openstack-uicore-foundation/lib/components/mui/table";
import MuiFormikTextField from "openstack-uicore-foundation/lib/components/mui/formik-inputs/textfield";
import MuiFormikSelect from "openstack-uicore-foundation/lib/components/mui/formik-inputs/select";
+import FileUploadInput from "../inputs/file-upload-input";
import useScrollToError from "../../hooks/useScrollToError";
import FormikTextEditor from "../inputs/formik-text-editor";
import MuiFormikAsyncAutocomplete from "../mui/formik-inputs/mui-formik-async-select";
@@ -99,6 +99,9 @@ const CompanyForm = ({
onRemove(initialEntity, field)
.catch(() => formik.setFieldValue(field, prevValue))
.finally(() => setIsSaving(false));
+ } else {
+ // also reached when cancelling an in-flight upload
+ setIsSaving(false);
}
};
@@ -370,7 +373,7 @@ const CompanyForm = ({
{T.translate("edit_company.logo")}
- setIsSaving(true)}
onError={() => setIsSaving(false)}
onRemove={handleLogoRemove("logo")}
- postUrl={`${window.FILE_UPLOAD_API_BASE_URL}/api/v1/files/upload`}
- djsConfig={{ withCredentials: true }}
maxFiles={1}
canAdd={!formik.values.logo}
mediaType={{
@@ -389,7 +390,7 @@ const CompanyForm = ({
{T.translate("edit_company.big_logo")}
- setIsSaving(true)}
onError={() => setIsSaving(false)}
onRemove={handleLogoRemove("big_logo")}
- postUrl={`${window.FILE_UPLOAD_API_BASE_URL}/api/v1/files/upload`}
- djsConfig={{ withCredentials: true }}
maxFiles={1}
canAdd={!formik.values.big_logo}
mediaType={{
diff --git a/src/components/forms/event-material-form.js b/src/components/forms/event-material-form.js
index b3322896f..4d5124a2a 100644
--- a/src/components/forms/event-material-form.js
+++ b/src/components/forms/event-material-form.js
@@ -16,8 +16,8 @@ import T from "i18n-react/dist/i18n-react";
import "awesome-bootstrap-checkbox/awesome-bootstrap-checkbox.css";
import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown";
import Input from "openstack-uicore-foundation/lib/components/inputs/text-input";
-import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3";
import TextEditorV3 from "openstack-uicore-foundation/lib/components/inputs/editor-input-v3";
+import FileUploadInput from "../inputs/file-upload-input";
import { scrollToError, hasErrors } from "../../utils/methods";
import {
ALLOWED_SLIDES_FORMATS,
@@ -237,14 +237,12 @@ const EventMaterialForm = ({ entity, errors, event, onSubmit }) => {
{" "}
{T.translate("edit_event_material.slide")} (max size 500Mb)
-
@@ -305,15 +303,13 @@ const EventMaterialForm = ({ entity, errors, event, onSubmit }) => {
entityState.media_upload_type.max_size / KB
}Mb )`}
-
diff --git a/src/components/inputs/__tests__/file-upload-input.test.js b/src/components/inputs/__tests__/file-upload-input.test.js
new file mode 100644
index 000000000..c91a40aa7
--- /dev/null
+++ b/src/components/inputs/__tests__/file-upload-input.test.js
@@ -0,0 +1,81 @@
+import React from "react";
+import { render } from "@testing-library/react";
+import FileUploadInput from "../file-upload-input";
+
+const renderedProps = {};
+
+jest.mock(
+ "openstack-uicore-foundation/lib/components/inputs/upload-input-v3",
+ () => ({
+ __esModule: true,
+ default: (props) => {
+ renderedProps.v3 = props;
+ return null;
+ }
+ })
+);
+
+jest.mock(
+ "openstack-uicore-foundation/lib/components/inputs/upload-input-v4",
+ () => ({
+ __esModule: true,
+ default: (props) => {
+ renderedProps.v4 = props;
+ return null;
+ }
+ })
+);
+
+const API_BASE = "https://file-upload-api.test";
+
+describe("FileUploadInput", () => {
+ const onUploadComplete = jest.fn();
+
+ beforeEach(() => {
+ delete renderedProps.v3;
+ delete renderedProps.v4;
+ window.FILE_UPLOAD_API_BASE_URL = API_BASE;
+ });
+
+ afterEach(() => {
+ delete window.FILE_UPLOAD_API_BASE_URL;
+ delete window.FILE_UPLOAD_USE_V4;
+ });
+
+ const renderInput = () =>
+ render(
+
+ );
+
+ it("uploads direct to storage through V4 when the flag is 'true'", () => {
+ window.FILE_UPLOAD_USE_V4 = "true";
+
+ renderInput();
+
+ expect(renderedProps.v3).toBeUndefined();
+ expect(renderedProps.v4.postUrl).toBe(`${API_BASE}/api/v1/files`);
+ expect(renderedProps.v4.onUploadComplete).toBe(onUploadComplete);
+ expect(renderedProps.v4).not.toHaveProperty("djsConfig");
+ expect(renderedProps.v4).not.toHaveProperty("parallelChunkUploads");
+ });
+
+ it.each([undefined, "false", "1"])(
+ "keeps the chunked V3 upload when the flag is %p",
+ (flag) => {
+ if (flag !== undefined) window.FILE_UPLOAD_USE_V4 = flag;
+
+ renderInput();
+
+ expect(renderedProps.v4).toBeUndefined();
+ expect(renderedProps.v3.postUrl).toBe(`${API_BASE}/api/v1/files/upload`);
+ expect(renderedProps.v3.djsConfig).toEqual({ withCredentials: true });
+ expect(renderedProps.v3.parallelChunkUploads).toBe(true);
+ expect(renderedProps.v3.onUploadComplete).toBe(onUploadComplete);
+ }
+ );
+});
diff --git a/src/components/inputs/file-upload-input.js b/src/components/inputs/file-upload-input.js
new file mode 100644
index 000000000..23b7db4aa
--- /dev/null
+++ b/src/components/inputs/file-upload-input.js
@@ -0,0 +1,54 @@
+/**
+ * Copyright 2026 OpenStack Foundation
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * */
+
+import React from "react";
+import PropTypes from "prop-types";
+import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3";
+import UploadInputV4 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v4";
+// uicore's components/index.css does not include the V4 rules.
+import "openstack-uicore-foundation/lib/css/components/inputs/upload-input-v4.css";
+
+// FILE_UPLOAD_USE_V4 selects direct-to-storage uploads. It is baked in at
+// build time: set it to anything but "true" and rebuild to roll back to the
+// chunked pipeline.
+const FileUploadInput = ({ parallelChunkUploads, ...rest }) => {
+ if (window.FILE_UPLOAD_USE_V4 === "true") {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+};
+
+FileUploadInput.propTypes = {
+ parallelChunkUploads: PropTypes.bool
+};
+
+FileUploadInput.defaultProps = {
+ parallelChunkUploads: false
+};
+
+export default FileUploadInput;
diff --git a/src/components/upload-dialog/index.js b/src/components/upload-dialog/index.js
index 718a6faf1..8414f83ff 100644
--- a/src/components/upload-dialog/index.js
+++ b/src/components/upload-dialog/index.js
@@ -14,12 +14,12 @@
import React, { useState } from "react";
import { Box, Divider, IconButton, Typography } from "@mui/material";
import PropTypes from "prop-types";
-import UploadInputV3 from "openstack-uicore-foundation/lib/components/inputs/upload-input-v3";
import CustomDialog from "openstack-uicore-foundation/lib/components/mui/custom-dialog";
import T from "i18n-react/dist/i18n-react";
import NoteAddIcon from "@mui/icons-material/NoteAdd";
import DeleteIcon from "@mui/icons-material/Delete";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
+import FileUploadInput from "../inputs/file-upload-input";
const MAX_PAGE_MODULE_UPLOAD_QTY = 1;
@@ -118,15 +118,13 @@ const UploadDialog = ({
>
) : (
- setUploadedFile(null)}
- postUrl={`${window.FILE_UPLOAD_API_BASE_URL}/api/v1/files/upload`}
- djsConfig={{ withCredentials: true }}
maxFiles={maxFiles}
canAdd={canAddMore()}
parallelChunkUploads
diff --git a/src/pages/sponsors/show-pages-list-page/__tests__/show-pages-list-page.test.js b/src/pages/sponsors/show-pages-list-page/__tests__/show-pages-list-page.test.js
index 8f50169df..add2a8f59 100644
--- a/src/pages/sponsors/show-pages-list-page/__tests__/show-pages-list-page.test.js
+++ b/src/pages/sponsors/show-pages-list-page/__tests__/show-pages-list-page.test.js
@@ -141,9 +141,11 @@ describe("ShowPagesListPage", () => {
}
}
);
- const editButton = screen.getByTestId("EditIcon").closest("button");
await act(async () => {
- await userEvent.click(editButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.edit" })
+ );
});
expect(getSummitSponsorshipTypes).toHaveBeenCalledWith(
DEFAULT_CURRENT_PAGE,
@@ -168,9 +170,11 @@ describe("ShowPagesListPage", () => {
}
}
);
- const editButton = screen.getByTestId("EditIcon").closest("button");
await act(async () => {
- await userEvent.click(editButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.edit" })
+ );
});
expect(getSummitSponsorshipTypes).toHaveBeenCalledWith(
DEFAULT_CURRENT_PAGE,
@@ -208,10 +212,13 @@ describe("ShowPagesListPage", () => {
}
}
);
- const deleteButtons = screen.getAllByTestId("DeleteIcon");
- const secondDeleteButton = deleteButtons[1].closest("button");
await act(async () => {
- await userEvent.click(secondDeleteButton);
+ await userEvent.click(
+ screen.getAllByTestId("row-actions-menu-trigger")[1]
+ );
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.delete" })
+ );
});
expect(
await screen.findByText("general.are_you_sure")
@@ -244,9 +251,11 @@ describe("ShowPagesListPage", () => {
}
}
);
- const deleteButton = screen.getByTestId("DeleteIcon").closest("button");
await act(async () => {
- await userEvent.click(deleteButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.delete" })
+ );
});
expect(
await screen.findByText("general.are_you_sure")
diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/cart-view.test.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/cart-view.test.js
index 935bdeb53..4e84c0c3a 100644
--- a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/cart-view.test.js
+++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/__tests__/cart-view.test.js
@@ -177,8 +177,9 @@ describe("CartView", () => {
expect(
screen.queryByRole("button", { name: "edit_sponsor.cart_tab.add_form" })
).not.toBeInTheDocument();
- expect(screen.queryByTestId("action-edit")).not.toBeInTheDocument();
- expect(screen.queryByTestId("action-delete")).not.toBeInTheDocument();
+ expect(
+ screen.queryByTestId("row-actions-menu-trigger")
+ ).not.toBeInTheDocument();
expect(
screen.queryByText("edit_sponsor.cart_tab.sponsor_note.title")
).not.toBeInTheDocument();
@@ -187,14 +188,19 @@ describe("CartView", () => {
).not.toBeInTheDocument();
});
- it("shows them on an Open cart", () => {
+ it("shows them on an Open cart", async () => {
renderCartView(createCart());
expect(
screen.getByRole("button", { name: "edit_sponsor.cart_tab.add_form" })
).toBeInTheDocument();
- expect(screen.getByTestId("action-edit")).toBeInTheDocument();
- expect(screen.getByTestId("action-delete")).toBeInTheDocument();
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ expect(
+ screen.getByRole("menuitem", { name: "general.edit" })
+ ).toBeInTheDocument();
+ expect(
+ screen.getByRole("menuitem", { name: "general.delete" })
+ ).toBeInTheDocument();
expect(
screen.getByText("edit_sponsor.cart_tab.sponsor_note.title")
).toBeInTheDocument();
diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/cart-view.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/cart-view.js
index 15b52a06b..1251bb1c8 100644
--- a/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/cart-view.js
+++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-cart-tab/components/cart-view.js
@@ -190,6 +190,8 @@ const CartView = ({
}
];
+ const amountIndex = tableColumns.findIndex((c) => c.columnKey === "amount");
+
return (
<>
@@ -231,11 +232,13 @@ const CartView = ({
}
confirmButtonColor="error"
>
- {/* gap skips manage items when hidden, trailing covers lock (+ edit, delete) */}
- {cartIsEditable ? (
-
- ) : (
-
+ {/* aligns the total under amount; MuiTable passes its column count */}
+ {(colCount) => (
+
)}
{isCardPaymentCart && (
diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-forms-tab/__tests__/sponsor-forms-tab.test.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-forms-tab/__tests__/sponsor-forms-tab.test.js
index 2ddd2ffc2..bb210e06b 100644
--- a/src/pages/sponsors/sponsor-page/tabs/sponsor-forms-tab/__tests__/sponsor-forms-tab.test.js
+++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-forms-tab/__tests__/sponsor-forms-tab.test.js
@@ -202,9 +202,11 @@ describe("SponsorFormsTab", () => {
const explicitRow = screen.getByText("Managed Form 1").closest("tr");
const implicitRow = screen.getByText("Managed Form 2").closest("tr");
- expect(within(explicitRow).getByTestId("DeleteIcon")).toBeInTheDocument();
expect(
- within(implicitRow).queryByTestId("DeleteIcon")
+ within(explicitRow).getByTestId("row-actions-menu-trigger")
+ ).toBeInTheDocument();
+ expect(
+ within(implicitRow).queryByTestId("row-actions-menu-trigger")
).not.toBeInTheDocument();
});
@@ -232,10 +234,13 @@ describe("SponsorFormsTab", () => {
expect(screen.getByText("Managed Form 1")).toBeInTheDocument();
expect(screen.getByText("Managed Form 2")).toBeInTheDocument();
- const deleteButtons = screen.getAllByTestId("DeleteIcon");
- const secondDeleteButton = deleteButtons[1].closest("button");
await act(async () => {
- await userEvent.click(secondDeleteButton);
+ await userEvent.click(
+ screen.getAllByTestId("row-actions-menu-trigger")[1]
+ );
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.delete" })
+ );
});
expect(
@@ -289,9 +294,11 @@ describe("SponsorFormsTab", () => {
}
});
- const deleteButton = screen.getByTestId("DeleteIcon").closest("button");
await act(async () => {
- await userEvent.click(deleteButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.delete" })
+ );
});
expect(
@@ -322,9 +329,11 @@ describe("SponsorFormsTab", () => {
store
});
- const deleteButton = screen.getByTestId("DeleteIcon").closest("button");
await act(async () => {
- await userEvent.click(deleteButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.delete" })
+ );
});
expect(
@@ -371,9 +380,11 @@ describe("SponsorFormsTab", () => {
}
});
- const deleteButton = screen.getByTestId("DeleteIcon").closest("button");
await act(async () => {
- await userEvent.click(deleteButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.delete" })
+ );
});
expect(
diff --git a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js
index b3e2a6cf3..f6cbe200d 100644
--- a/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js
+++ b/src/pages/sponsors/sponsor-page/tabs/sponsor-pages-tab/__tests__/sponsor-pages-tab.test.js
@@ -205,9 +205,11 @@ describe("SponsorPagesTab", () => {
}
);
- const editButton = screen.getByTestId("EditIcon").closest("button");
await act(async () => {
- await userEvent.click(editButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.edit" })
+ );
});
expect(getSponsorCustomizedPage).toHaveBeenCalledWith(1);
@@ -355,9 +357,11 @@ describe("SponsorPagesTab", () => {
}
);
- const editButton = screen.getByTestId("EditIcon").closest("button");
await act(async () => {
- await userEvent.click(editButton);
+ await userEvent.click(screen.getByTestId("row-actions-menu-trigger"));
+ await userEvent.click(
+ screen.getByRole("menuitem", { name: "general.edit" })
+ );
});
await waitFor(() => {
diff --git a/yarn.lock b/yarn.lock
index 6cc854497..e70fb240a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2708,6 +2708,11 @@
resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.6.1.tgz#13e09a32d7a8b7060fe38304788ebf4197cd2149"
integrity sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==
+"@transloadit/prettier-bytes@^0.3.4":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@transloadit/prettier-bytes/-/prettier-bytes-0.3.5.tgz#0cca83975293e3f4990229914942c69714122ede"
+ integrity sha512-xF4A3d/ZyX2LJWeQZREZQw+qFX4TGQ8bGVP97OLRt6sPO6T0TNHBFTuRHOJh7RNmYOBmQ9MHxpolD9bXihpuVA==
+
"@tybys/wasm-util@^0.10.0":
version "0.10.1"
resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414"
@@ -3350,6 +3355,50 @@
resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777"
integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==
+"@uppy/aws-s3@^5.1.0":
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/@uppy/aws-s3/-/aws-s3-5.1.0.tgz#7ffa3534a23ed0a81b7ab0c21a916c1b688cf5fc"
+ integrity sha512-UBz+shrtDbnOf11AboDrkc9Fq2Cdf8HbFftE+gqfxig6fkv5rHpHhBCLkl8wCGAq+X/CxdqvvNhm/OM23Uzw2w==
+ dependencies:
+ "@uppy/companion-client" "^5.1.1"
+ "@uppy/utils" "^7.1.4"
+
+"@uppy/companion-client@^5.1.1":
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/@uppy/companion-client/-/companion-client-5.1.1.tgz#5bfeda3312ba2b70e94d4fd73a31d0f7757884c0"
+ integrity sha512-DzrOWTbIZHvtgAFXBMYHk2wD27NjpBSVhY2tEiEIUhPd2CxbFRZjHM/N3HOt3VwZEAP471QWFLlJRWPcIY3A2Q==
+ dependencies:
+ "@uppy/utils" "^7.1.1"
+ namespace-emitter "^2.0.1"
+ p-retry "^6.1.0"
+
+"@uppy/core@^5.2.0":
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/@uppy/core/-/core-5.2.0.tgz#baeb0f9f1ef5bec1882eac912f5a41094af69f84"
+ integrity sha512-uvfNyz4cnaplt7LYJmEZHuqOuav0tKp4a9WKJIaH6iIj7XiqYvS2J5SEByexAlUFlzefOAyjzj4Ja2dd/8aMrw==
+ dependencies:
+ "@transloadit/prettier-bytes" "^0.3.4"
+ "@uppy/store-default" "^5.0.0"
+ "@uppy/utils" "^7.1.4"
+ lodash "^4.17.21"
+ mime-match "^1.0.2"
+ namespace-emitter "^2.0.1"
+ nanoid "^5.0.9"
+ preact "^10.5.13"
+
+"@uppy/store-default@^5.0.0":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@uppy/store-default/-/store-default-5.0.0.tgz#2466162857a999b8c99051426e5f412e2f34cb26"
+ integrity sha512-hQtCSQ1yGiaval/wVYUWquYGDJ+bpQ7e4FhUUAsRQz1x1K+o7NBtjfp63O9I4Ks1WRoKunpkarZ+as09l02cPw==
+
+"@uppy/utils@^7.1.1", "@uppy/utils@^7.1.4":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@uppy/utils/-/utils-7.2.0.tgz#10212e92d8b57ff9d854276d056e98fdcd4643c9"
+ integrity sha512-6lC246qszMv6bTyl/+QyHwrudgeguWkA94ME1wHn+a6uRAvmtAEaUManIfGqTJfoKvWAiCJqdJPl5xRJjhAloQ==
+ dependencies:
+ lodash "^4.17.23"
+ preact "^10.26.10"
+
"@videojs/http-streaming@2.16.3":
version "2.16.3"
resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-2.16.3.tgz#d9b460c3716436327dbab4b1faeb2a767f05dcef"
@@ -8406,7 +8455,7 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
-lodash@>=4.17.21, lodash@^4.14.1, lodash@^4.16.2, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.2.1:
+lodash@>=4.17.21, lodash@^4.14.1, lodash@^4.16.2, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.23, lodash@^4.2.1:
version "4.18.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.18.1.tgz#ff2b66c1f6326d59513de2407bf881439812771c"
integrity sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==
@@ -8608,6 +8657,13 @@ mime-db@1.52.0:
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5"
integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+mime-match@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/mime-match/-/mime-match-1.0.2.tgz#3f87c31e9af1a5fd485fb9db134428b23bbb7ba8"
+ integrity sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==
+ dependencies:
+ wildcard "^1.1.0"
+
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34, mime-types@~2.1.35:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
@@ -8811,11 +8867,21 @@ mux.js@6.0.1:
"@babel/runtime" "^7.11.2"
global "^4.4.0"
+namespace-emitter@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz#978d51361c61313b4e6b8cf6f3853d08dfa2b17c"
+ integrity sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g==
+
nanoid@^3.3.11:
version "3.3.11"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b"
integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==
+nanoid@^5.0.9:
+ version "5.1.16"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.1.16.tgz#fe345c0a1f9007c32fbb5c139e1208bfd3f41ef7"
+ integrity sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ==
+
napi-postinstall@^0.3.0:
version "0.3.4"
resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.4.tgz#7af256d6588b5f8e952b9190965d6b019653bbb9"
@@ -9076,10 +9142,10 @@ open@^10.0.3:
is-inside-container "^1.0.0"
wsl-utils "^0.1.0"
-openstack-uicore-foundation@5.0.73-beta.1:
- version "5.0.73-beta.1"
- resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.73-beta.1.tgz#95274f8a31004e38d3c201d778f5d7f05928c8e5"
- integrity sha512-+UTWgAy7DTZB3bToiASYo1ggtnEsG1MDNTc6Jr43l+HXUbB8NBStHrjR+xwuMKs4YnmSIpCfi8U26yjG029Ggw==
+openstack-uicore-foundation@5.0.75:
+ version "5.0.75"
+ resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.75.tgz#fa9d9c0bd6d4ee3e55c4a3dd17ed86096a25a21c"
+ integrity sha512-4zkRwoCPdguBX9W+aj4tWgpivwIltBL3l/U5yaDdAYPMEIiXfWod34vRfqJKryTPgbb1XCJtIDs2T4GgsNAlTQ==
dependencies:
use-sync-external-store "^1.6.0"
@@ -9149,7 +9215,7 @@ p-map@^2.0.0:
resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
-p-retry@^6.2.0:
+p-retry@^6.1.0, p-retry@^6.2.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.2.1.tgz#81828f8dc61c6ef5a800585491572cc9892703af"
integrity sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==
@@ -9670,6 +9736,11 @@ postcss@^8.4.17, postcss@^8.4.33:
picocolors "^1.1.1"
source-map-js "^1.2.1"
+preact@^10.26.10, preact@^10.5.13:
+ version "10.29.8"
+ resolved "https://registry.yarnpkg.com/preact/-/preact-10.29.8.tgz#fc85b82dc2474e245b1430b51781d417361f5fc3"
+ integrity sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==
+
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
@@ -12152,6 +12223,11 @@ which@^2.0.1, which@^2.0.2:
dependencies:
isexe "^2.0.0"
+wildcard@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-1.1.2.tgz#a7020453084d8cd2efe70ba9d3696263de1710a5"
+ integrity sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng==
+
wildcard@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67"