Skip to content

Commit 4dd516c

Browse files
awoloszyn22dbadurachriskari
authored
fix: Page title flickering on smaller screen width (#4292)
* fix: page title flickering on smaller screen width * fix: fix ToolbarSeparator import * use toolbar button * chore: replace button with toolbarbutton within toolbar * test: fix double type in search * fix spacing * fix data source update * minor improvements * fix: rerendering * remove unused imports --------- Co-authored-by: Damian Badura <damian.badura@sap.com> Co-authored-by: chriskari <chriskari@gmx.de>
1 parent 32e46ce commit 4dd516c

File tree

14 files changed

+279
-250
lines changed

14 files changed

+279
-250
lines changed

src/components/Extensibility/ExtensibilityInjections.jsx

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { usePrepareResourceUrl } from 'resources/helpers';
1111
import pluralize from 'pluralize';
1212
import { useGet } from 'shared/hooks/BackendAPI/useGet';
1313

14-
export const ExtensibilityInjectionCore = ({ resMetaData, root }) => {
14+
export function ExtensibilityInjectionCore({ resMetaData, root }) {
1515
const isStatic = resMetaData?.general?.type === 'static';
1616
const staticResource = {
1717
kind: root?.kind || 'Namespace',
@@ -28,7 +28,7 @@ export const ExtensibilityInjectionCore = ({ resMetaData, root }) => {
2828
resourceType: pluralize(resource?.kind || '').toLowerCase(),
2929
});
3030

31-
const { data } = useGet(resourceUrl, {
31+
const { data, loading } = useGet(resourceUrl, {
3232
pollingInterval: 3000,
3333
skip: !resourceUrl,
3434
});
@@ -61,6 +61,10 @@ export const ExtensibilityInjectionCore = ({ resMetaData, root }) => {
6161
// eslint-disable-next-line react-hooks/exhaustive-deps
6262
}, [resource, isStatic, filter, JSON.stringify(items)]);
6363

64+
if (loading && !data) {
65+
return null;
66+
}
67+
6468
// there may be a moment when `resMetaData` is undefined (e.g. when switching the namespace)
6569
if (!resource && !isStatic) {
6670
return null;
@@ -80,22 +84,15 @@ export const ExtensibilityInjectionCore = ({ resMetaData, root }) => {
8084
context={injection.target}
8185
/>
8286
);
83-
};
87+
}
8488

85-
const ExtensibilityInjections = ({ destination, slot, root }) => {
89+
export default function ExtensibilityInjections({ destination, slot, root }) {
8690
const injections = useGetInjections(destination, slot);
87-
let itemList = [];
88-
(injections || []).forEach((injection, index) => {
89-
itemList.push(
90-
<ExtensibilityInjection
91-
resMetaData={injection}
92-
root={root}
93-
key={index}
94-
/>,
95-
);
96-
});
97-
return itemList;
98-
};
91+
92+
return (injections || []).map((injection, index) => (
93+
<ExtensibilityInjection resMetaData={injection} root={root} key={index} />
94+
));
95+
}
9996

10097
const ExtensibilityInjection = ({ resMetaData, root }) => {
10198
const { urlPath, defaultPlaceholder } = resMetaData?.general || {};
@@ -114,5 +111,3 @@ const ExtensibilityInjection = ({ resMetaData, root }) => {
114111
</TranslationBundleContext.Provider>
115112
);
116113
};
117-
118-
export default ExtensibilityInjections;

src/components/Extensibility/components/ExternalLink.jsx

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
import { useTranslation } from 'react-i18next';
77
import { useJsonata } from '../hooks/useJsonata';
88

9-
import { Button, Icon, Link } from '@ui5/webcomponents-react';
9+
import { Button, Icon, Link, ToolbarButton } from '@ui5/webcomponents-react';
1010
import { isNil } from 'lodash';
1111

1212
const makeHref = ({ linkObject, value }) => {
@@ -63,6 +63,24 @@ export const ExternalLink = ({
6363

6464
if (isNil(value)) return emptyLeafPlaceholder;
6565

66+
if (
67+
structure.type === 'button' &&
68+
structure.targets.find((t) => t.slot === 'details-header')
69+
) {
70+
return (
71+
<ToolbarButton
72+
accessibleRole="Link"
73+
accessibleName={tExt(value)}
74+
accessibleDescription="Open in new tab link"
75+
endIcon="inspect"
76+
onClick={() => {
77+
const newWindow = window.open(href, '_blank', 'noopener, noreferrer');
78+
if (newWindow) newWindow.opener = null;
79+
}}
80+
text={tExt(value)}
81+
/>
82+
);
83+
}
6684
if (structure.type === 'button') {
6785
return (
6886
<Button

src/components/Extensibility/components/Widget.jsx

Lines changed: 73 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from 'react';
1+
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
22
import { isNil } from 'lodash';
33
import { useTranslation } from 'react-i18next';
44

@@ -37,71 +37,91 @@ InlineWidget.copyFunction = (props, Renderer, defaultCopyFunction) =>
3737
? Renderer.copyFunction(props, Renderer, defaultCopyFunction)
3838
: defaultCopyFunction(props, Renderer, defaultCopyFunction);
3939

40-
function SingleWidget({ inlineRenderer, Renderer, ...props }) {
41-
const InlineRenderer = inlineRenderer || SimpleRenderer;
42-
const CopyableWrapper = ({ children }) => {
43-
const isRendererCopyable =
44-
typeof Renderer.copyable === 'function'
45-
? Renderer.copyable(Renderer)
46-
: Renderer.copyable;
47-
48-
const jsonata = useJsonata({
49-
resource: props.originalResource,
50-
parent: props.singleRootResource,
51-
embedResource: props.embedResource,
52-
scope: props.scope,
53-
value: props.value,
54-
arrayItems: props.arrayItems,
55-
});
56-
const [textToCopy, setTextToCopy] = useState('');
40+
const defaultCopyFunction = ({ value }) =>
41+
typeof value === 'object' ? JSON.stringify(value) : value;
5742

58-
const defaultCopyFunction = ({ value }) =>
59-
typeof value === 'object' ? JSON.stringify(value) : value;
43+
const CopyableWrapper = memo(function CopyableWrapper({
44+
children,
45+
Renderer,
46+
...props
47+
}) {
48+
const isRendererCopyable = useMemo(() => {
49+
return typeof Renderer.copyable === 'function'
50+
? Renderer.copyable(Renderer)
51+
: Renderer.copyable;
52+
}, [Renderer]);
53+
54+
const jsonata = useJsonata({
55+
resource: props.originalResource,
56+
parent: props.singleRootResource,
57+
embedResource: props.embedResource,
58+
scope: props.scope,
59+
value: props.value,
60+
arrayItems: props.arrayItems,
61+
});
62+
const [textToCopy, setTextToCopy] = useState('');
6063

61-
const copyFunction =
64+
const copyFunction = useCallback(
65+
(props, Renderer, defaultCopyFunction, linkObject) =>
6266
typeof Renderer.copyFunction === 'function'
63-
? Renderer.copyFunction
64-
: defaultCopyFunction;
65-
66-
useEffect(() => {
67-
if (!props.structure.copyable || !isRendererCopyable) return;
68-
jsonata(props?.structure?.link).then((linkObject) => {
69-
setTextToCopy(
70-
copyFunction(props, Renderer, defaultCopyFunction, linkObject),
71-
);
72-
});
73-
// eslint-disable-next-line react-hooks/exhaustive-deps
74-
}, [
75-
props?.structure?.link,
76-
props.structure.copyable,
77-
isRendererCopyable,
78-
props.originalResource,
79-
props.singleRootResource,
80-
props.embedResource,
81-
props.scope,
82-
props.value,
83-
props.arrayItems,
84-
]);
85-
86-
if (!props.structure.copyable || !isRendererCopyable) return children;
67+
? Renderer.copyFunction(
68+
props,
69+
Renderer,
70+
defaultCopyFunction,
71+
linkObject,
72+
)
73+
: defaultCopyFunction(props, Renderer, defaultCopyFunction, linkObject),
74+
[],
75+
);
8776

88-
return (
89-
<CopiableText textToCopy={textToCopy} disabled={!textToCopy}>
90-
{children}
91-
</CopiableText>
92-
);
93-
};
77+
useEffect(() => {
78+
if (!props.structure.copyable || !isRendererCopyable) return;
79+
jsonata(props?.structure?.link).then((linkObject) => {
80+
setTextToCopy(
81+
copyFunction(props, Renderer, defaultCopyFunction, linkObject),
82+
);
83+
});
84+
// eslint-disable-next-line react-hooks/exhaustive-deps
85+
}, [
86+
props?.structure?.link,
87+
props.structure.copyable,
88+
isRendererCopyable,
89+
props.originalResource,
90+
props.singleRootResource,
91+
props.embedResource,
92+
props.scope,
93+
props.value,
94+
props.arrayItems,
95+
copyFunction,
96+
jsonata,
97+
]);
98+
99+
if (!props.structure.copyable || !isRendererCopyable) return children;
100+
101+
return (
102+
<CopiableText textToCopy={textToCopy} disabled={!textToCopy}>
103+
{children}
104+
</CopiableText>
105+
);
106+
});
107+
108+
const SingleWidget = memo(function SingleWidget({
109+
inlineRenderer,
110+
Renderer,
111+
...props
112+
}) {
113+
const InlineRenderer = inlineRenderer || SimpleRenderer;
94114

95115
return Renderer.inline ? (
96116
<InlineRenderer {...props}>
97-
<CopyableWrapper structure={props.structure} value={props.value}>
117+
<CopyableWrapper {...props} Renderer={Renderer}>
98118
<Renderer {...props} />
99119
</CopyableWrapper>
100120
</InlineRenderer>
101121
) : (
102122
<Renderer {...props} />
103123
);
104-
}
124+
});
105125

106126
export function Widget({
107127
structure,
@@ -150,7 +170,6 @@ export function Widget({
150170
structure.source,
151171
index,
152172
structure.visibility,
153-
childValue,
154173
originalResource,
155174
singleRootResource,
156175
embedResource,

src/components/Extensibility/contexts/DataSources.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import pluralize from 'pluralize';
2-
import { createContext, useEffect, useRef, FC, useState } from 'react';
2+
import { createContext, FC, useEffect, useRef, useState } from 'react';
33
import { useAtomValue } from 'jotai';
44

55
import { useFetch } from 'shared/hooks/BackendAPI/useFetch';
6-
import { useObjectState } from 'shared/useObjectState';
76
import jp from 'jsonpath';
87
import { jsonataWrapper } from '../helpers/jsonataWrapper';
98
import { activeNamespaceIdAtom } from 'state/activeNamespaceIdAtom';
9+
import { useObjectState } from 'shared/useObjectState';
1010
import { resourcesConditionsAtom } from 'state/resourceConditionsAtom';
1111

1212
export interface Resource {
@@ -57,10 +57,7 @@ export interface DataSourcesContextType {
5757
store: Store;
5858
dataSources: DataSources;
5959
getRelatedResourceInPath: (path: string) => string | undefined;
60-
requestRelatedResource: (
61-
resource: Resource,
62-
dataSourceName: string,
63-
) => Promise<any>;
60+
requestRelatedResource: (resource: Resource, dataSourceName: string) => any;
6461
}
6562

6663
export const DataSourcesContext = createContext<DataSourcesContextType>(
@@ -243,7 +240,7 @@ export const DataSourcesContextProvider: FC<Props> = ({
243240
} else if (store?.[dataSourceName]?.loading) {
244241
return store?.[dataSourceName]?.firstFetch;
245242
} else {
246-
return Promise.resolve(store?.[dataSourceName]?.data);
243+
return store?.[dataSourceName]?.data;
247244
}
248245
};
249246

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,42 @@
11
import { useAtomValue } from 'jotai';
22
import { injectionsAtom } from 'state/navigation/extensionsAtom';
3+
import { useMemo } from 'react';
34

45
export const useGetInjections = (location, slot) => {
56
const injections = useAtomValue(injectionsAtom);
6-
let filteredInjections = [];
77

8-
(injections || []).forEach((injection) => {
9-
const target = injection.injection.targets.find(
10-
(t) =>
11-
t.location?.toLowerCase() === location?.toLowerCase() &&
12-
t.slot?.toLowerCase() === slot?.toLowerCase(),
13-
);
14-
if (target) {
15-
filteredInjections.push({
16-
...injection,
17-
injection: {
18-
...injection.injection,
19-
target: target,
20-
},
8+
const filteredInjections = useMemo(() => {
9+
let filteredInjections = [];
10+
11+
(injections || []).forEach((injection) => {
12+
const target = injection.injection.targets.find(
13+
(t) =>
14+
t.location?.toLowerCase() === location?.toLowerCase() &&
15+
t.slot?.toLowerCase() === slot?.toLowerCase(),
16+
);
17+
if (target) {
18+
filteredInjections.push({
19+
...injection,
20+
injection: {
21+
...injection.injection,
22+
target: target,
23+
},
24+
});
25+
}
26+
});
27+
28+
if (filteredInjections.length !== 0) {
29+
filteredInjections.sort((a, b) => {
30+
if (a.injection?.order != null && b.injection?.order != null)
31+
return a.injection?.order - b.injection?.order;
32+
else if (a.injection.name && b.injection.name)
33+
return a.injection.name.localeCompare(b.injection.name);
34+
else return a;
2135
});
2236
}
23-
});
24-
if (filteredInjections.length !== 0) {
25-
filteredInjections.sort((a, b) => {
26-
if (a.injection?.order != null && b.injection?.order != null)
27-
return a.injection?.order - b.injection?.order;
28-
else if (a.injection.name && b.injection.name)
29-
return a.injection.name.localeCompare(b.injection.name);
30-
else return a;
31-
});
32-
}
37+
38+
return filteredInjections;
39+
}, [injections, location, slot]);
3340

3441
return filteredInjections;
3542
};

src/components/Modules/providers/KymaModuleProvider.jsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { createContext, useContext, useEffect, useState } from 'react';
22
import { createPortal } from 'react-dom';
3-
import { Button } from '@ui5/webcomponents-react';
3+
import { ToolbarButton } from '@ui5/webcomponents-react';
44

55
import { cloneDeep } from 'lodash';
66
import { t } from 'i18next';
@@ -118,9 +118,11 @@ export function KymaModuleContextProvider({
118118
const customHeaderActions = (
119119
<>
120120
{maintenanceBadge}
121-
<Button onClick={() => handleResourceDelete({})} design="Transparent">
122-
{t('common.buttons.delete-module')}
123-
</Button>
121+
<ToolbarButton
122+
onClick={() => handleResourceDelete({})}
123+
design="Transparent"
124+
text={t('common.buttons.delete-module')}
125+
/>
124126
</>
125127
);
126128

0 commit comments

Comments
 (0)