diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx
index 35a42b300d..cbabe87e08 100644
--- a/src/components/App/App.tsx
+++ b/src/components/App/App.tsx
@@ -39,6 +39,7 @@ import { useAfterInitHook } from 'state/useAfterInitHook';
import useSidebarCondensed from 'sidebar/useSidebarCondensed';
import { useGetValidationEnabledSchemas } from 'state/validationEnabledSchemasAtom';
import { useGetKymaResources } from 'state/kymaResourcesAtom';
+import { Spinner } from 'shared/components/Spinner/Spinner';
export default function App() {
const language = useRecoilValue(languageAtom);
@@ -59,7 +60,7 @@ export default function App() {
useResourceSchemas();
useSidebarCondensed();
- useAuthHandler();
+ const { isLoading } = useAuthHandler();
useGetConfiguration();
useGetExtensions();
useGetExtensibilitySchemas();
@@ -75,6 +76,10 @@ export default function App() {
useAfterInitHook(kubeconfigIdState);
useGetKymaResources();
+ if (isLoading) {
+ return ;
+ }
+
return (
diff --git a/src/components/Extensibility/components-form/GenericList.js b/src/components/Extensibility/components-form/GenericList.js
index 18341edf0d..d8afcb3342 100644
--- a/src/components/Extensibility/components-form/GenericList.js
+++ b/src/components/Extensibility/components-form/GenericList.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import { useState } from 'react';
import { PluginStack, useUIStore } from '@ui-schema/ui-schema';
import { Button } from '@ui5/webcomponents-react';
import { useTranslation } from 'react-i18next';
diff --git a/src/components/Extensibility/components/FeaturedCard/FeaturedCard.scss b/src/components/Extensibility/components/FeaturedCard/FeaturedCard.scss
index fca4f1243b..2e1e9020c2 100644
--- a/src/components/Extensibility/components/FeaturedCard/FeaturedCard.scss
+++ b/src/components/Extensibility/components/FeaturedCard/FeaturedCard.scss
@@ -3,6 +3,11 @@
margin-left: 0.25rem !important;
margin-right: 0.25rem !important;
}
+
+.banner-carousel {
+ height: fit-content;
+}
+
.feature-card {
position: relative;
display: flex;
diff --git a/src/components/HelmReleases/HelmReleasesList.js b/src/components/HelmReleases/HelmReleasesList.js
index ababeb4705..8ace16c496 100644
--- a/src/components/HelmReleases/HelmReleasesList.js
+++ b/src/components/HelmReleases/HelmReleasesList.js
@@ -72,36 +72,34 @@ function HelmReleasesList() {
];
return (
- <>
-
a.releaseName.localeCompare(b.releaseName),
- }}
- searchSettings={{
- textSearchProperties: [
- 'recentRelease.chart.metadata.name',
- 'releaseName',
- ],
- }}
- emptyListProps={{
- subtitleText: ResourceDescription,
- url: docsURL,
- showButton: false,
- }}
- readOnly
- description={ResourceDescription}
- />
- >
+ a.releaseName.localeCompare(b.releaseName),
+ }}
+ searchSettings={{
+ textSearchProperties: [
+ 'recentRelease.chart.metadata.name',
+ 'releaseName',
+ ],
+ }}
+ emptyListProps={{
+ subtitleText: ResourceDescription,
+ url: docsURL,
+ showButton: false,
+ }}
+ readOnly
+ description={ResourceDescription}
+ />
);
}
diff --git a/src/components/KymaModules/KymaModulesList.js b/src/components/KymaModules/KymaModulesList.js
index 52ed92a242..3f7800fa4e 100644
--- a/src/components/KymaModules/KymaModulesList.js
+++ b/src/components/KymaModules/KymaModulesList.js
@@ -421,7 +421,7 @@ export default function KymaModulesList({
layoutNumber="StartColumn"
windowTitle={t('kyma-modules.title')}
headerContent={
-
+
diff --git a/src/header/NamespaceDropdown/NamespaceDropdown.tsx b/src/header/NamespaceDropdown/NamespaceDropdown.tsx
index 0d316f4db4..d62d4d2823 100644
--- a/src/header/NamespaceDropdown/NamespaceDropdown.tsx
+++ b/src/header/NamespaceDropdown/NamespaceDropdown.tsx
@@ -11,7 +11,7 @@ export function NamespaceDropdown() {
let namespaces = [];
- if (allNamespaces.length > 0) {
+ if (allNamespaces && allNamespaces.length > 0) {
namespaces.push(
+ allNamespaces?.map(ns =>
namespaces.push(),
);
diff --git a/src/hooks/useAvailableNamespaces.ts b/src/hooks/useAvailableNamespaces.ts
index 288426131f..beddfe01b7 100644
--- a/src/hooks/useAvailableNamespaces.ts
+++ b/src/hooks/useAvailableNamespaces.ts
@@ -28,7 +28,7 @@ export function useAvailableNamespaces() {
useEffect(() => {
if (error) {
- setNamespaces([]);
+ setNamespaces(null);
return;
}
const filteredNamespaces = allNamespaces
diff --git a/src/resources/createResourceRoutes.js b/src/resources/createResourceRoutes.js
index 845145da95..9c1052751c 100644
--- a/src/resources/createResourceRoutes.js
+++ b/src/resources/createResourceRoutes.js
@@ -84,17 +84,31 @@ const ColumnWrapper = ({
});
const elementListProps = usePrepareListProps({
- ...props,
+ resourceCustomType: props.resourceCustomType,
+ resourceType: props.resourceType,
+ resourceI18Key: props.resourceI18Key,
+ apiGroup: props.apiGroup,
+ apiVersion: props.apiVersion,
+ hasDetailsView: props.hasDetailsView,
});
const elementDetailsProps = usePrepareDetailsProps({
- ...props,
+ resourceCustomType: props.resourceCustomType,
+ resourceType: props.resourceType,
+ resourceI18Key: props.resourceI18Key,
+ apiGroup: props.apiGroup,
+ apiVersion: props.apiVersion,
resourceName: layoutState?.midColumn?.resourceName ?? resourceName,
namespaceId: layoutState?.midColumn?.namespaceId ?? namespaceId,
+ showYamlTab: props.showYamlTab,
});
const elementCreateProps = usePrepareCreateProps({
- ...props,
+ resourceCustomType: props.resourceCustomType,
+ resourceType: props.resourceType,
+ resourceTypeForTitle: props.resourceType,
+ apiGroup: props.apiGroup,
+ apiVersion: props.apiVersion,
});
const listComponent = React.cloneElement(list, {
@@ -122,16 +136,13 @@ const ColumnWrapper = ({
detailsMidColumn = detailsComponent;
}
- const { schema, loading } = useGetSchema({
+ const { schema } = useGetSchema({
resource: {
group: props?.apiGroup,
version: props.apiVersion,
kind: props?.resourceType.slice(0, -1),
},
});
- if (loading) {
- return null;
- }
const createMidColumn = (
+
{
+const useGetHeaderHeight = (dynamicPageRef, tabContainerRef) => {
const [headerHeight, setHeaderHeight] = useState(undefined);
+ const [tabContainerHeight, setTabContainerHeight] = useState(undefined);
+
useEffect(() => {
const headerObserver = new ResizeObserver(([header]) => {
setHeaderHeight(header.contentRect.height);
});
+
+ const tabContainerObserver = new ResizeObserver(([tabContainer]) => {
+ setTabContainerHeight(tabContainer.contentRect.height);
+ });
+
if (dynamicPageRef.current) {
- // wait for the custom element to be defined (adjust the tag-name if you're using the scoping feature)
+ // Wait for the custom element to be defined
void customElements.whenDefined('ui5-dynamic-page').then(() => {
const shadowRoot = dynamicPageRef.current?.shadowRoot;
@@ -40,12 +45,13 @@ const useGetHeaderHeight = dynamicPageRef => {
return;
}
- // wait for the shadowRoot to be populated
+ // Wait for the shadowRoot to be populated
const shadowRootObserver = new MutationObserver(() => {
const header = shadowRoot.querySelector('header');
+
if (header) {
- shadowRootObserver.disconnect();
headerObserver.observe(header);
+ shadowRootObserver.disconnect();
}
});
@@ -53,21 +59,24 @@ const useGetHeaderHeight = dynamicPageRef => {
const header = shadowRoot.querySelector('header');
if (header) {
headerObserver.observe(header);
- } else {
- return;
}
} else if (shadowRoot instanceof Node) {
shadowRootObserver.observe(shadowRoot, { childList: true });
- } else {
- return;
}
});
}
+
+ if (tabContainerRef.current) {
+ tabContainerObserver.observe(tabContainerRef.current);
+ }
+
return () => {
headerObserver.disconnect();
+ tabContainerObserver.disconnect();
};
- }, [dynamicPageRef]);
- return headerHeight;
+ }, [dynamicPageRef, tabContainerRef]);
+
+ return { headerHeight, tabContainerHeight };
};
const Column = ({ title, children, columnSpan, image, style = {} }) => {
@@ -110,7 +119,11 @@ export const DynamicPageComponent = ({
const [selectedSectionIdState, setSelectedSectionIdState] = useState('view');
const dynamicPageRef = useRef(null);
- const headerHeight = useGetHeaderHeight(dynamicPageRef);
+ const tabContainerRef = useRef(null);
+ const { headerHeight, tabContainerHeight } = useGetHeaderHeight(
+ dynamicPageRef,
+ tabContainerRef,
+ );
const handleColumnClose = () => {
window.history.pushState(
@@ -246,44 +259,13 @@ export const DynamicPageComponent = ({
);
- const headerTitle = inlineEditForm ? (
-
-
- {title}
-
- {protectedResource && (
-
- {protectedResourceWarning}
-
- )}
- {description && (
-
- )}
-
- }
- actionsBar={actionsBar}
- />
- ) : (
+ const headerTitle = (
-
-
- ) : (
-
-
-
- )
+
+
+
) : null;
- const [stickyHeaderHeight, setStickyHeaderHeight] = useState(0);
+ const handlePageRef = dynamicPage => {
+ if (dynamicPageRef) {
+ if (typeof dynamicPageRef === 'function') {
+ dynamicPageRef(dynamicPage);
+ } else if (dynamicPageRef.current !== undefined) {
+ dynamicPageRef.current = dynamicPage;
+ }
+ }
- useEffect(() => {
- setTimeout(() => {
- setStickyHeaderHeight(
- (document.querySelector('.page-header')?.querySelector('header')
- ?.clientHeight ?? 0) +
- (document
- .querySelector('.page-header')
- ?.querySelector('ui5-tabcontainer')?.clientHeight ?? 0),
- );
- });
- }, []);
+ const button = dynamicPage?.shadowRoot?.querySelector(
+ 'ui5-dynamic-page-header-actions',
+ );
+ if (button) {
+ button.style['display'] = 'none';
+ }
+ };
if (inlineEditForm) {
return (
- {
+ onSelectedSectionChange={e => {
if (isFormOpen.formOpen) {
e.preventDefault();
}
@@ -363,37 +340,40 @@ export const DynamicPageComponent = ({
isFormOpen,
setIsFormOpen,
() => {
- setSelectedSectionIdState(e.detail.sectionId);
+ setSelectedSectionIdState(e.detail.selectedSectionId);
setIsResourceEdited({
isEdited: false,
});
},
);
- if (e.detail.sectionId === 'edit') {
+ if (e.detail.selectedSectionI === 'edit') {
setIsFormOpen({ formOpen: true });
}
}}
+ ref={dynamicPage => handlePageRef(dynamicPage)}
>
-
- {content}
-
- {
+ const mode = event.detail.tab.getAttribute('data-mode');
+ setSelectedSectionIdState(mode);
+ }}
>
- {inlineEditForm(stickyHeaderHeight)}
-
-
+
+
+
+
+ {selectedSectionIdState === 'view' && content}
+
+ {selectedSectionIdState === 'edit' &&
+ inlineEditForm(headerHeight + tabContainerHeight)}
+
);
}
@@ -404,7 +384,7 @@ export const DynamicPageComponent = ({
titleArea={headerTitle}
headerArea={headerContent}
footerArea={footer}
- ref={dynamicPageRef}
+ ref={dynamicPage => handlePageRef(dynamicPage)}
>
{typeof content === 'function' ? content(headerHeight) : content}
diff --git a/src/shared/components/DynamicPageComponent/DynamicPageComponent.scss b/src/shared/components/DynamicPageComponent/DynamicPageComponent.scss
index 1d512b03ed..a1122a9d0b 100644
--- a/src/shared/components/DynamicPageComponent/DynamicPageComponent.scss
+++ b/src/shared/components/DynamicPageComponent/DynamicPageComponent.scss
@@ -4,6 +4,7 @@
ui5-dynamic-page-title {
justify-content: center;
min-height: 3rem;
+ padding-left: 2rem;
}
.bold-title {
@@ -27,10 +28,6 @@
display: none;
}
- [data-component-name='ObjectPageTitleMiddleSection'] > div {
- flex-basis: 100%;
- }
-
&__actions {
display: flex;
align-items: center;
@@ -57,6 +54,17 @@
position: static;
padding: unset;
}
+
+ .tab-container {
+ position: sticky;
+ z-index: 1;
+ }
+}
+
+ui5-dynamic-page {
+ .no-shadow {
+ box-shadow: none;
+ }
}
.header-wrapper {
@@ -99,10 +107,6 @@
}
}
-ui5-button[data-component-name='ObjectPageAnchorBarExpandBtn'] {
- display: none;
-}
-
@media (max-width: 768px) {
.column-wrapper {
display: flex;
@@ -110,8 +114,3 @@ ui5-button[data-component-name='ObjectPageAnchorBarExpandBtn'] {
gap: 12px;
}
}
-
-[data-component-name='DynamicPageContent'],
-[data-component-name='ObjectPageContent'] {
- padding: 0 !important;
-}
diff --git a/src/shared/components/GenericList/GenericList.js b/src/shared/components/GenericList/GenericList.js
index 2c310262fb..e8cf5dab4a 100644
--- a/src/shared/components/GenericList/GenericList.js
+++ b/src/shared/components/GenericList/GenericList.js
@@ -32,6 +32,7 @@ import pluralize from 'pluralize';
import { isResourceEditedState } from 'state/resourceEditedAtom';
import { isFormOpenState } from 'state/formOpenAtom';
import { handleActionIfFormOpen } from '../UnsavedMessageBox/helpers';
+import './GenericList.scss';
const defaultSort = {
name: nameLocaleSort,
@@ -113,9 +114,7 @@ export const GenericList = ({
}, [pageSize, pagination]);
const { i18n, t } = useTranslation();
- const [currentPage, setCurrentPage] = React.useState(
- pagination?.initialPage || 1,
- );
+ const [currentPage, setCurrentPage] = useState(pagination?.initialPage || 1);
const [filteredEntries, setFilteredEntries] = useState(() =>
sorting(sort, entries),
@@ -197,7 +196,7 @@ export const GenericList = ({
const renderTableBody = () => {
if (serverDataError) {
return (
-
+
{getErrorMessage(serverDataError)}
);
@@ -205,7 +204,7 @@ export const GenericList = ({
if (serverDataLoading) {
return (
-
+
);
diff --git a/src/shared/components/UI5Panel/UI5Panel.tsx b/src/shared/components/UI5Panel/UI5Panel.tsx
index 1aaa63aac5..f2c7dd47f6 100644
--- a/src/shared/components/UI5Panel/UI5Panel.tsx
+++ b/src/shared/components/UI5Panel/UI5Panel.tsx
@@ -38,7 +38,7 @@ export const UI5Panel = ({
if (headerTop !== '0')
setTimeout(() => {
const stickyHeader = document
- .querySelector('ui5-panel')
+ .querySelector('.resource-form--panel')
?.shadowRoot?.querySelector('.ui5-panel-root')
?.querySelector(
'.ui5-panel-heading-wrapper.ui5-panel-heading-wrapper-sticky',
diff --git a/src/state/authDataAtom.ts b/src/state/authDataAtom.ts
index c598899f2b..a5dbdfe90d 100644
--- a/src/state/authDataAtom.ts
+++ b/src/state/authDataAtom.ts
@@ -1,6 +1,6 @@
import { parseOIDCparams } from 'components/Clusters/components/oidc-params';
import { UserManager, User } from 'oidc-client-ts';
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { atom, useSetRecoilState, useRecoilValue, RecoilState } from 'recoil';
import { KubeconfigNonOIDCAuth, KubeconfigOIDCAuth } from 'types';
@@ -137,6 +137,7 @@ export function useAuthHandler() {
const setAuth = useSetRecoilState(authDataState);
const navigate = useNavigate();
const setLastFetched = useSetRecoilState(openapiLastFetchedState);
+ const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
console.log(
@@ -145,14 +146,17 @@ export function useAuthHandler() {
if (!cluster) {
setAuth(null);
+ setIsLoading(false);
} else {
// don't do the auth flow on cluster list (e.g. after refresh, while the OIDC cluster is still connected)
if (window.location.pathname === '/clusters') {
+ setIsLoading(false);
return;
}
const userCredentials = cluster.currentContext?.user?.user;
if (hasNonOidcAuth(userCredentials)) {
setAuth(userCredentials as KubeconfigNonOIDCAuth);
+ setIsLoading(false);
} else {
const onAfterLogin = () => {
if (!getPreviousPath() || getPreviousPath() === '/clusters') {
@@ -166,8 +170,12 @@ export function useAuthHandler() {
navigate('/cluster/' + encodeURIComponent(cluster.name));
}
}
+ setIsLoading(false);
+ };
+ const onError = () => {
+ navigate('/clusters');
+ setIsLoading(false);
};
- const onError = () => navigate('/clusters');
handleLogin({
userCredentials: userCredentials as KubeconfigOIDCAuth,
@@ -181,6 +189,8 @@ export function useAuthHandler() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [cluster]);
+
+ return { isLoading };
}
export const authDataState: RecoilState = atom({
diff --git a/src/state/namespacesAtom.ts b/src/state/namespacesAtom.ts
index bf94bf69d3..c03fd3b363 100644
--- a/src/state/namespacesAtom.ts
+++ b/src/state/namespacesAtom.ts
@@ -1,8 +1,8 @@
import { atom, RecoilState } from 'recoil';
-export type NamespacesState = string[];
+export type NamespacesState = string[] | null;
-const defaultValue: string[] = [];
+const defaultValue = null;
export const namespacesState: RecoilState = atom<
NamespacesState