From c3ab4920878a363660b31e5018b04c07420f2f8e Mon Sep 17 00:00:00 2001
From: hodanoori <107242553+hodanoori@users.noreply.github.com>
Date: Thu, 17 Oct 2024 16:42:55 +0200
Subject: [PATCH 1/2] fix(heureka): fixes embedded prop handling (#530)
* fix(heureka): corrects embedded prop handling
* chore(heureka): adds changeset
* chore(heureka): sets embedded default value within the global store slice
* chore(heureka): removes endpoints check from useQueryClientFn
---
.changeset/eighty-steaks-wink.md | 6 ++++++
apps/heureka/src/App.jsx | 10 ++--------
apps/heureka/src/components/CustomAppShell.jsx | 5 +++--
apps/heureka/src/hooks/useQueryClientFn.js | 4 ++--
apps/heureka/src/lib/slices/createGlobalsSlice.js | 2 +-
5 files changed, 14 insertions(+), 13 deletions(-)
create mode 100644 .changeset/eighty-steaks-wink.md
diff --git a/.changeset/eighty-steaks-wink.md b/.changeset/eighty-steaks-wink.md
new file mode 100644
index 000000000..dc62cd2c9
--- /dev/null
+++ b/.changeset/eighty-steaks-wink.md
@@ -0,0 +1,6 @@
+---
+"@cloudoperators/juno-app-heureka": patch
+"@cloudoperators/juno-app-greenhouse": patch
+---
+
+This fixes the embedded prop handling, ensuring it is passed correctly to AppShell.
diff --git a/apps/heureka/src/App.jsx b/apps/heureka/src/App.jsx
index 7c2fa38db..60e94249f 100644
--- a/apps/heureka/src/App.jsx
+++ b/apps/heureka/src/App.jsx
@@ -3,19 +3,18 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import React, { useLayoutEffect } from "react"
+import React from "react"
import styles from "./styles.scss?inline"
import { AppShellProvider, CodeBlock } from "@cloudoperators/juno-ui-components"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { MessagesProvider } from "@cloudoperators/juno-messages-provider"
import AsyncWorker from "./components/AsyncWorker"
import { ErrorBoundary } from "react-error-boundary"
-import { useGlobalsActions, StoreProvider } from "./components/StoreProvider"
+import { StoreProvider } from "./components/StoreProvider"
import PanelManager from "./components/shared/PanelManager"
import CustomAppShell from "./components/CustomAppShell"
function App(props = {}) {
- const { setEmbedded, setApiEndpoint } = useGlobalsActions()
const preErrorClasses = `
custom-error-pre
border-theme-error
@@ -24,11 +23,6 @@ function App(props = {}) {
w-full
`
- useLayoutEffect(() => {
- setApiEndpoint(props.endpoint)
- if (props.embedded === "true" || props.embedded === true) setEmbedded(true)
- }, [])
-
const fallbackRender = ({ error }) => {
return (
diff --git a/apps/heureka/src/components/CustomAppShell.jsx b/apps/heureka/src/components/CustomAppShell.jsx
index 490ecf6eb..7ac694b70 100644
--- a/apps/heureka/src/components/CustomAppShell.jsx
+++ b/apps/heureka/src/components/CustomAppShell.jsx
@@ -5,7 +5,7 @@
import React from "react"
import { AppShell, PageHeader, TopNavigation, TopNavigationItem } from "@cloudoperators/juno-ui-components"
-import { useGlobalsActions, useGlobalsActiveView } from "./StoreProvider"
+import { useGlobalsActions, useGlobalsActiveView, useGlobalsEmbedded } from "./StoreProvider"
import ServicesView from "./services/ServicesView"
import IssueMatchesView from "./issueMatches/IssueMatchesView"
import ComponentsView from "./components/ComponentsView"
@@ -21,6 +21,7 @@ const VIEW_CONFIG = {
const CustomAppShell = ({ children }) => {
const { setActiveView, setShowPanel } = useGlobalsActions()
const activeView = useGlobalsActiveView()
+ const embedded = useGlobalsEmbedded()
const handleNavItemChange = (item) => {
setActiveView(item)
@@ -40,7 +41,7 @@ const CustomAppShell = ({ children }) => {
const ActiveComponent = VIEW_CONFIG[activeView]?.component
return (
-
} topNavigation={topNavigation}>
+
} topNavigation={topNavigation} embedded={embedded}>
{ActiveComponent &&
}
{children}
diff --git a/apps/heureka/src/hooks/useQueryClientFn.js b/apps/heureka/src/hooks/useQueryClientFn.js
index 49361d265..b569950b4 100644
--- a/apps/heureka/src/hooks/useQueryClientFn.js
+++ b/apps/heureka/src/hooks/useQueryClientFn.js
@@ -24,7 +24,7 @@ const useQueryClientFn = () => {
As stated in getQueryDefaults, the order of registration of query defaults does matter. Since the first matching defaults are returned by getQueryDefaults, the registration should be made in the following order: from the least generic key to the most generic one. This way, in case of specific key, the first matching one would be the expected one.
*/
useEffect(() => {
- if (!queryClient || !endpoint) return
+ if (!queryClient) return
// Services main query
queryClient.setQueryDefaults(["ServicesMain"], {
@@ -135,7 +135,7 @@ const useQueryClientFn = () => {
// Set queryClientFnReady to true once
setQueryClientFnReady(true)
- }, [queryClient, endpoint])
+ }, [queryClient])
}
export default useQueryClientFn
diff --git a/apps/heureka/src/lib/slices/createGlobalsSlice.js b/apps/heureka/src/lib/slices/createGlobalsSlice.js
index 8aedd6100..7dac0dca5 100644
--- a/apps/heureka/src/lib/slices/createGlobalsSlice.js
+++ b/apps/heureka/src/lib/slices/createGlobalsSlice.js
@@ -8,7 +8,7 @@ import constants from "../../components/shared/constants"
const createGlobalsSlice = (set, get, options) => ({
globals: {
- embedded: false, //Set to true if app is to be embedded in another existing app or page.
+ embedded: options?.embedded === true || options?.embedded === "true", //Set to true if app is to be embedded in another existing app or page.
apiEndpoint: options?.apiEndpoint, //The API endpoint to use for fetching data.
isUrlStateSetup: false, //Set to true when the URL state has been set up.
queryClientFnReady: false, //Set to true when the queryClient function is ready to be used.
From 436f35a28330097f38e7c985a9f6a5ceff1d143f Mon Sep 17 00:00:00 2001
From: Guoda <121792659+guoda-puidokaite@users.noreply.github.com>
Date: Fri, 18 Oct 2024 09:09:17 +0200
Subject: [PATCH 2/2] chore(ui): migrate Search Input component to Typescript
(#528)
* chore(ui): convert SearchInput to Typescript and add types
* chore(ui): remove deprecated code and change tests to vitest
* chore(ui): update docs, tests and other small changes
* chore(ui): add deprecated code for Filter component tests
* chore(ui): generate changeset and fix test requiring .js component
* chore(ui): remove deprecated .js story
* chore(ui): refactored existing code
* chore(ui): improve tests
* chore(ui): improve conditional rendering
* fix(ui): add missing newline
* chore(ui): fix conditional rendering and update docs with removing outdated comment
* chore(ui): fix conditional check
---------
Co-authored-by: Esther Schmitz
---
.changeset/perfect-socks-beam.md | 5 +
.../src/components/Filters/Filters.test.js | 2 +-
.../JsonViewer/JsonViewer.component.js | 2 +-
.../SearchInput/SearchInput.component.tsx | 225 ++++++++++++++++++
...put.stories.js => SearchInput.stories.tsx} | 2 +-
.../SearchInput/SearchInput.test.tsx | 160 +++++++++++++
.../SearchInput/{index.js => index.ts} | 0
.../components/SearchInput/searchinput.scss | 10 +-
.../SearchInput/SearchInput.component.js | 0
.../SearchInput/SearchInput.test.js | 0
.../src/deprecated_js/SearchInput/index.js | 6 +
.../SearchInput/searchinput.scss | 6 +
12 files changed, 411 insertions(+), 7 deletions(-)
create mode 100644 .changeset/perfect-socks-beam.md
create mode 100644 packages/ui-components/src/components/SearchInput/SearchInput.component.tsx
rename packages/ui-components/src/components/SearchInput/{SearchInput.stories.js => SearchInput.stories.tsx} (91%)
create mode 100644 packages/ui-components/src/components/SearchInput/SearchInput.test.tsx
rename packages/ui-components/src/components/SearchInput/{index.js => index.ts} (100%)
rename packages/ui-components/src/{components => deprecated_js}/SearchInput/SearchInput.component.js (100%)
rename packages/ui-components/src/{components => deprecated_js}/SearchInput/SearchInput.test.js (100%)
create mode 100644 packages/ui-components/src/deprecated_js/SearchInput/index.js
create mode 100644 packages/ui-components/src/deprecated_js/SearchInput/searchinput.scss
diff --git a/.changeset/perfect-socks-beam.md b/.changeset/perfect-socks-beam.md
new file mode 100644
index 000000000..14e8d53ad
--- /dev/null
+++ b/.changeset/perfect-socks-beam.md
@@ -0,0 +1,5 @@
+---
+"@cloudoperators/juno-ui-components": minor
+---
+
+Migrate the Search Input component to TypeScript
diff --git a/packages/ui-components/src/components/Filters/Filters.test.js b/packages/ui-components/src/components/Filters/Filters.test.js
index 0565bc20a..9620854f9 100644
--- a/packages/ui-components/src/components/Filters/Filters.test.js
+++ b/packages/ui-components/src/components/Filters/Filters.test.js
@@ -7,7 +7,7 @@ import * as React from "react"
import { render, screen } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import { Filters } from "./index"
-import { SearchInput } from "../SearchInput/index"
+import { SearchInput } from "../../deprecated_js/SearchInput"
describe("Filters", () => {
test("renders Filters", async () => {
diff --git a/packages/ui-components/src/components/JsonViewer/JsonViewer.component.js b/packages/ui-components/src/components/JsonViewer/JsonViewer.component.js
index 3abdd0a22..fa7da3576 100644
--- a/packages/ui-components/src/components/JsonViewer/JsonViewer.component.js
+++ b/packages/ui-components/src/components/JsonViewer/JsonViewer.component.js
@@ -6,7 +6,7 @@
import PropTypes from "prop-types"
import React, { useContext, useLayoutEffect } from "react"
import * as themes from "./themes"
-import { SearchInput } from "../SearchInput/SearchInput.component"
+import { SearchInput } from "../../deprecated_js/SearchInput"
// DEFAULT THEME (DARK)
const DEFAULT_THEME = {
diff --git a/packages/ui-components/src/components/SearchInput/SearchInput.component.tsx b/packages/ui-components/src/components/SearchInput/SearchInput.component.tsx
new file mode 100644
index 000000000..9794c38ec
--- /dev/null
+++ b/packages/ui-components/src/components/SearchInput/SearchInput.component.tsx
@@ -0,0 +1,225 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import React, { useState, useEffect, ChangeEvent, KeyboardEvent, MouseEvent, useCallback } from "react"
+
+import { Icon } from "../Icon"
+import { Stack } from "../Stack"
+
+import "./searchinput.scss"
+
+export interface SearchInputProps {
+ /**
+ * Specifies the name attribute for the input element.
+ */
+ name?: string
+ /**
+ * Determines the visual styling variant of the SearchInput component.
+ * - "default": Standard search input styling.
+ * - "hero": A larger search input intended for standalone use on a dedicated search page, akin to the initial Google search page.
+ * - "rounded": A search input with rounded edges.
+ */
+ variant?: "rounded" | "hero" | "default"
+ /**
+ * Disables the search input when set to true.
+ */
+ disabled?: boolean
+ /**
+ * Custom placeholder text displayed in the search input.
+ */
+ placeholder?: string
+ /**
+ * Initial value for the search input.
+ */
+ value?: string
+ /**
+ * Controls the autocomplete attribute of the input element.
+ * Pass a valid autocomplete value.
+ * We do not enforce validity.
+ */
+ autoComplete?: string
+ /**
+ * Determines whether to show the 'Clear' button.
+ */
+ clear?: boolean
+ /**
+ * Pass an optional CSS class to apply to the search input.
+ */
+ className?: string
+ /**
+ * Callback function invoked when a search is triggered, either by pressing the 'Enter' key or by clicking the search icon.
+ */
+ onSearch?: (_value: string) => void
+ /**
+ * Click handler for the search icon.
+ */
+ onClick?: (_event: MouseEvent) => void
+ /**
+ * Change handler for the search input.
+ */
+ onChange?: (_event: ChangeEvent) => void
+ /**
+ * KeyPress handler for the search input. By default, triggers the onSearch function when the 'Enter' key is pressed.
+ */
+ onKeyPress?: (_event: KeyboardEvent) => void
+ /**
+ * Click handler for the 'Clear' button.
+ */
+ onClear?: (_event: MouseEvent) => void
+}
+
+const getWrapperStyles = (variant: "rounded" | "hero" | "default"): string => {
+ const baseStyles = "jn-relative jn-inline-block jn-win-max"
+ switch (variant) {
+ case "rounded":
+ return `${baseStyles} jn-w-auto`
+ case "hero":
+ return `${baseStyles} jn-w-full`
+ default:
+ return `${baseStyles} jn-w-auto`
+ }
+}
+
+const getSearchStyles = (variant: "rounded" | "hero" | "default"): string => {
+ const baseStyles = `
+ jn-bg-theme-textinput
+ jn-text-theme-high
+ jn-shadow
+ jn-w-full
+ focus:jn-outline-none
+ focus:jn-ring-2
+ focus:jn-ring-theme-focus
+ disabled:jn-cursor-not-allowed
+ disabled:jn-opacity-50
+ `
+
+ const roundedStyles = "jn-rounded-full focus:jn-rounded-full"
+ switch (variant) {
+ case "rounded":
+ return `${baseStyles} ${roundedStyles} jn-text-base jn-w-auto jn-pl-3 jn-pr-16 jn-py-1`
+ case "hero":
+ return `${baseStyles} ${roundedStyles} jn-text-lg jn-w-full jn-pl-6 jn-pr-20 jn-py-2.5`
+ default:
+ return `${baseStyles} jn-rounded jn-text-base jn-leading-4 jn-pl-4 jn-pr-16 jn-py-2.5`
+ }
+}
+
+const getIconWrapperStyles = (variant: "rounded" | "hero" | "default"): string => {
+ switch (variant) {
+ case "rounded":
+ return "jn-absolute jn-inline-flex jn-right-3 jn-top-1"
+ case "hero":
+ return "jn-absolute jn-inline-flex jn-right-5"
+ default:
+ return "jn-absolute jn-inline-flex jn-right-3 jn-top-2"
+ }
+}
+
+const getClearIconStyles = (variant: "rounded" | "hero" | "default"): string => {
+ switch (variant) {
+ case "hero":
+ return "jn-mr-2.5"
+ default:
+ return "jn-mr-2"
+ }
+}
+
+const getClearIconSize = (variant: "rounded" | "hero" | "default"): string => {
+ return variant === "hero" ? "24" : "18"
+}
+
+/**
+ * A SearchInput is a controlled input component for searching.
+ * It provides a text field to enter a search query and optional clear and search icons.
+ * Three styling variants are supported: "rounded", "hero", and "default".
+ */
+export const SearchInput: React.FC = ({
+ value = "",
+ name = "search",
+ variant = "default",
+ disabled = false,
+ clear = true,
+ onSearch,
+ onChange,
+ onClick,
+ onKeyPress,
+ onClear,
+ autoComplete = "off",
+ placeholder = "Search…",
+ className = "",
+ ...props
+}) => {
+ const [val, setValue] = useState(value)
+
+ useEffect(() => {
+ setValue(value)
+ }, [value])
+
+ const handleInputChange = useCallback(
+ (event: ChangeEvent): void => {
+ setValue(event.target.value)
+ onChange?.(event)
+ },
+ [onChange]
+ )
+
+ const handleKeyPress = useCallback(
+ (event: KeyboardEvent): void => {
+ if (event.key === "Enter" && onSearch) {
+ onSearch(val)
+ }
+ onKeyPress?.(event)
+ },
+ [onSearch, onKeyPress, val]
+ )
+
+ const handleSearchClick = useCallback(
+ (event: MouseEvent): void => {
+ onSearch?.(val)
+ onClick?.(event)
+ },
+ [onSearch, onClick, val]
+ )
+
+ const handleClearClick = useCallback(
+ (event: MouseEvent): void => {
+ setValue("")
+ onClear?.(event)
+ },
+ [onClear]
+ )
+
+ return (
+
+
+
+
+ {clear && val?.length > 0 && (
+
+ )}
+
+
+
+
+ )
+}
diff --git a/packages/ui-components/src/components/SearchInput/SearchInput.stories.js b/packages/ui-components/src/components/SearchInput/SearchInput.stories.tsx
similarity index 91%
rename from packages/ui-components/src/components/SearchInput/SearchInput.stories.js
rename to packages/ui-components/src/components/SearchInput/SearchInput.stories.tsx
index ebeaf199f..ddf1b7dba 100644
--- a/packages/ui-components/src/components/SearchInput/SearchInput.stories.js
+++ b/packages/ui-components/src/components/SearchInput/SearchInput.stories.tsx
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { SearchInput } from "./index.js"
+import { SearchInput } from "./"
export default {
title: "Components/SearchInput",
diff --git a/packages/ui-components/src/components/SearchInput/SearchInput.test.tsx b/packages/ui-components/src/components/SearchInput/SearchInput.test.tsx
new file mode 100644
index 000000000..966fe55e0
--- /dev/null
+++ b/packages/ui-components/src/components/SearchInput/SearchInput.test.tsx
@@ -0,0 +1,160 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+import * as React from "react"
+import { render, screen } from "@testing-library/react"
+import userEvent from "@testing-library/user-event"
+import { describe, expect, test, vi } from "vitest"
+import { SearchInput } from "./"
+
+describe("SearchInput Component", () => {
+ describe("Basic Rendering", () => {
+ test("should render a valid HTML input type 'search'", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toBeInTheDocument()
+ expect(screen.getByRole("searchbox")).toHaveAttribute("type", "search")
+ })
+ })
+
+ describe("Placeholder Handling", () => {
+ test("should render a default placeholder 'Search…'", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toHaveAttribute("placeholder", "Search…")
+ })
+
+ test("should render a specific placeholder when provided", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toHaveAttribute("placeholder", "My custom placeholder")
+ })
+ })
+
+ describe("Value Handling", () => {
+ test("should render a specific value when provided", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toHaveValue("blah")
+ })
+
+ test("should render a Clear icon if the field has a value", () => {
+ render()
+ expect(screen.getByTitle("Clear")).toBeInTheDocument()
+ })
+
+ test("should update the input's value when typing", async () => {
+ render()
+ const input = screen.getByRole("searchbox")
+ await userEvent.type(input, "abc")
+ expect(input).toHaveValue("abc")
+ })
+ })
+
+ describe("Attributes and ClassNames", () => {
+ test("should render with the default name 'search'", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toHaveAttribute("name", "search")
+ })
+
+ test("should render with a specific name when provided", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toHaveAttribute("name", "searchbox")
+ })
+
+ test("should apply all provided props", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toHaveAttribute("name", "My shiny little Message")
+ })
+
+ test("should apply custom classNames when provided", () => {
+ render()
+ expect(screen.getByRole("search")).toHaveClass("my-custom-class")
+ })
+ })
+
+ describe("Disabled State", () => {
+ test("should disable the search input when 'disabled' prop is passed", () => {
+ render()
+ expect(screen.getByRole("searchbox")).toBeDisabled()
+ })
+ })
+
+ describe("Event Handlers", () => {
+ test("should trigger 'onSearch' handler when search button is clicked", async () => {
+ const handleSearch = vi.fn()
+ render()
+ await userEvent.click(screen.getByRole("button", { name: /search/i }))
+ expect(handleSearch).toHaveBeenCalledTimes(1)
+ })
+
+ test("should trigger 'onClick' handler when search button is clicked", async () => {
+ const handleClick = vi.fn()
+ render()
+ await userEvent.click(screen.getByRole("button", { name: /search/i }))
+ expect(handleClick).toHaveBeenCalledTimes(1)
+ })
+
+ test("should trigger both 'onClick' and 'onSearch' handlers when search button is clicked if both are provided", async () => {
+ const handleClick = vi.fn()
+ const handleSearch = vi.fn()
+ render()
+ await userEvent.click(screen.getByRole("button", { name: /search/i }))
+ expect(handleClick).toHaveBeenCalledTimes(1)
+ expect(handleSearch).toHaveBeenCalledTimes(1)
+ })
+
+ test("should trigger 'onSearch' handler when Enter key is pressed", async () => {
+ const handleSearch = vi.fn()
+ render()
+ await userEvent.type(screen.getByRole("searchbox"), "{enter}")
+ expect(handleSearch).toHaveBeenCalledTimes(1)
+ })
+
+ test("should not trigger 'onSearch' handler when keys other than Enter are pressed", async () => {
+ const handleSearch = vi.fn()
+ render()
+ await userEvent.type(screen.getByRole("searchbox"), "{shift}")
+ expect(handleSearch).toHaveBeenCalledTimes(0)
+ })
+
+ test("should trigger 'onKeyPress' handler when any key is pressed, including Enter", async () => {
+ const handleKeyPress = vi.fn()
+ render()
+ await userEvent.type(screen.getByRole("searchbox"), "{enter}abc")
+ expect(handleKeyPress).toHaveBeenCalledTimes(4)
+ })
+
+ test("should trigger 'onChange' handler as text is typed", async () => {
+ const handleChange = vi.fn()
+ render()
+ await userEvent.type(screen.getByRole("searchbox"), "abc")
+ expect(handleChange).toHaveBeenCalledTimes(3)
+ })
+
+ test("should trigger 'onClear' handler when Clear icon is clicked", async () => {
+ const handleClear = vi.fn()
+ render()
+ await userEvent.click(screen.getByTitle("Clear"))
+ expect(handleClear).toHaveBeenCalledTimes(1)
+ })
+ })
+
+ describe("Clear Button Logic", () => {
+ test("should render a Clear icon if the field has a value", () => {
+ render()
+ expect(screen.getByTitle("Clear")).toBeInTheDocument()
+ })
+
+ test("should clear the input when the Clear icon is clicked", async () => {
+ render()
+ await userEvent.click(screen.getByTitle("Clear"))
+ expect(screen.getByRole("searchbox")).toHaveValue("")
+ })
+
+ test("should trigger 'onClear' handler when the Clear icon is clicked", async () => {
+ const handleClear = vi.fn()
+ render()
+ await userEvent.click(screen.getByTitle("Clear"))
+ expect(handleClear).toHaveBeenCalledTimes(1)
+ })
+ })
+})
diff --git a/packages/ui-components/src/components/SearchInput/index.js b/packages/ui-components/src/components/SearchInput/index.ts
similarity index 100%
rename from packages/ui-components/src/components/SearchInput/index.js
rename to packages/ui-components/src/components/SearchInput/index.ts
diff --git a/packages/ui-components/src/components/SearchInput/searchinput.scss b/packages/ui-components/src/components/SearchInput/searchinput.scss
index a8bfe21cc..e08f1f05b 100644
--- a/packages/ui-components/src/components/SearchInput/searchinput.scss
+++ b/packages/ui-components/src/components/SearchInput/searchinput.scss
@@ -1,6 +1,8 @@
-// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
-// SPDX-License-Identifier: Apache-2.0
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
.juno-search-input::-webkit-search-cancel-button {
- -webkit-appearance: none;
-}
\ No newline at end of file
+ -webkit-appearance: none;
+}
diff --git a/packages/ui-components/src/components/SearchInput/SearchInput.component.js b/packages/ui-components/src/deprecated_js/SearchInput/SearchInput.component.js
similarity index 100%
rename from packages/ui-components/src/components/SearchInput/SearchInput.component.js
rename to packages/ui-components/src/deprecated_js/SearchInput/SearchInput.component.js
diff --git a/packages/ui-components/src/components/SearchInput/SearchInput.test.js b/packages/ui-components/src/deprecated_js/SearchInput/SearchInput.test.js
similarity index 100%
rename from packages/ui-components/src/components/SearchInput/SearchInput.test.js
rename to packages/ui-components/src/deprecated_js/SearchInput/SearchInput.test.js
diff --git a/packages/ui-components/src/deprecated_js/SearchInput/index.js b/packages/ui-components/src/deprecated_js/SearchInput/index.js
new file mode 100644
index 000000000..3c1d79629
--- /dev/null
+++ b/packages/ui-components/src/deprecated_js/SearchInput/index.js
@@ -0,0 +1,6 @@
+/*
+ * SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+export { SearchInput } from "./SearchInput.component"
diff --git a/packages/ui-components/src/deprecated_js/SearchInput/searchinput.scss b/packages/ui-components/src/deprecated_js/SearchInput/searchinput.scss
new file mode 100644
index 000000000..ec67207fd
--- /dev/null
+++ b/packages/ui-components/src/deprecated_js/SearchInput/searchinput.scss
@@ -0,0 +1,6 @@
+// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
+// SPDX-License-Identifier: Apache-2.0
+
+.juno-search-input::-webkit-search-cancel-button {
+ -webkit-appearance: none;
+}