Skip to content

Commit d9689f2

Browse files
committed
Merge branch 'main' into feat/fb-clear-all
2 parents 3fc702f + 84ae471 commit d9689f2

File tree

9 files changed

+131
-16
lines changed

9 files changed

+131
-16
lines changed

packages/main/scripts/generateI18n.mjs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,24 @@ spawnSync('npx', ['prettier', '--write', path.resolve(SRC_I18N_PROPERTIES, 'i18n
5555
stdio: [0, 1, 2],
5656
});
5757

58-
// generate Assets.js
58+
// generate Assets.js and Assets-fetch.js
5959
const jsonImports = await readdir(TARGET_I18N_JSON_IMPORTS);
6060

6161
const assets = [`import '@ui5/webcomponents/dist/Assets.js';`, `import '@ui5/webcomponents-fiori/dist/Assets.js';`];
62+
const assetsFetch = [
63+
`import '@ui5/webcomponents/dist/Assets-fetch.js';`,
64+
`import '@ui5/webcomponents-fiori/dist/Assets-fetch.js';`,
65+
];
66+
const assetsNode = [
67+
`import '@ui5/webcomponents/dist/Assets-node.js';`,
68+
`import '@ui5/webcomponents-fiori/dist/Assets-node.js';`,
69+
];
6270

6371
for (const file of jsonImports) {
6472
if (file.includes('-fetch')) {
65-
//todo: add to Assets-fetch.js
73+
assetsFetch.push(`import './json-imports/${file}';`);
6674
} else if (file.includes('-node')) {
67-
//todo: add to Assets-node.js
75+
assetsNode.push(`import './json-imports/${file}';`);
6876
} else {
6977
assets.push(`import './json-imports/${file}';`);
7078
}
@@ -74,3 +82,13 @@ await writeFile(
7482
path.resolve(DIST_DIR, 'Assets.js'),
7583
await prettier.format(assets.join('\n'), { ...prettierConfig, parser: 'babel' }),
7684
);
85+
86+
await writeFile(
87+
path.resolve(DIST_DIR, 'Assets-fetch.js'),
88+
await prettier.format(assetsFetch.join('\n'), { ...prettierConfig, parser: 'babel' }),
89+
);
90+
91+
await writeFile(
92+
path.resolve(DIST_DIR, 'Assets-node.js'),
93+
await prettier.format(assetsNode.join('\n'), { ...prettierConfig, parser: 'babel' }),
94+
);

packages/main/src/components/AnalyticalTable/AnalyticalTable.cy.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1539,7 +1539,16 @@ describe('AnalyticalTable', () => {
15391539
'opacity',
15401540
'0.4',
15411541
);
1542+
cy.mount(<AnalyticalTable data={[]} columns={columns} loading loadingDelay={0} alwaysShowBusyIndicator />);
1543+
cy.get('[data-component-name="AnalyticalTableLoadingPlaceholder"]').should('not.exist');
1544+
cy.get('.ui5-busy-indicator-busy-area', { timeout: 2000 }).should('be.visible');
1545+
cy.get('[data-component-name="AnalyticalTableContainerWithScrollbar"] > :not([class*="busyIndicator"])').should(
1546+
'have.css',
1547+
'opacity',
1548+
'0.4',
1549+
);
15421550
cy.mount(<AnalyticalTable data={data} columns={columns} loading />);
1551+
cy.get('[data-component-name="AnalyticalTableLoadingPlaceholder"]').should('not.exist');
15431552
cy.get('.ui5-busy-indicator-busy-area', { timeout: 2000 }).should('be.visible');
15441553
cy.get('[data-component-name="AnalyticalTableContainerWithScrollbar"] > :not([class*="busyIndicator"])').should(
15451554
'have.css',

packages/main/src/components/AnalyticalTable/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ const measureElement = (el: HTMLElement) => {
107107
*/
108108
const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTypes>((props, ref) => {
109109
const {
110-
alternateRowColor,
111110
adjustTableHeightOnPopIn,
111+
alternateRowColor,
112+
alwaysShowBusyIndicator,
112113
className,
113114
columnOrder,
114115
columns,
@@ -749,7 +750,7 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
749750
className={classNames.tableContainerWithScrollBar}
750751
data-component-name="AnalyticalTableContainerWithScrollbar"
751752
>
752-
{loading && !!rows.length && (
753+
{loading && (!!rows.length || alwaysShowBusyIndicator) && (
753754
<BusyIndicator
754755
className={classNames.busyIndicator}
755756
active={true}
@@ -816,7 +817,7 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
816817
tabIndex={0}
817818
className={classNames.noDataContainer}
818819
>
819-
{loading ? (
820+
{loading && !alwaysShowBusyIndicator ? (
820821
<TablePlaceholder
821822
columns={visibleColumns}
822823
rows={minRows}

packages/main/src/components/AnalyticalTable/types/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ export interface AnalyticalTablePropTypes extends Omit<CommonProps, 'title'> {
707707
/**
708708
* Indicates whether a loading indicator should be shown.
709709
*
710-
* __Note:__ If the data array is not empty and loading is set to `true` a `BusyIndicator` will be displayed on top of the table, otherwise a skeleton placeholder will be shown.
710+
* __Note:__ If the data array is not empty and loading is set to `true` a `BusyIndicator` will be displayed on top of the table, otherwise a skeleton placeholder will be shown. You can control this behavior via the `alwaysShowBusyIndicator` prop.
711711
*/
712712
loading?: boolean;
713713
/**
@@ -720,6 +720,10 @@ export interface AnalyticalTablePropTypes extends Omit<CommonProps, 'title'> {
720720
* Setting this prop to `true` will show an overlay on top of the AnalyticalTable content preventing users from interacting with it.
721721
*/
722722
showOverlay?: boolean;
723+
/**
724+
* If `true`, always shows the `BusyIndicator` component when loading instead of the skeleton loader.
725+
*/
726+
alwaysShowBusyIndicator?: boolean;
723727
/**
724728
* Defines the text shown if the data array is empty or a filtered table doesn't return results.
725729
*

packages/main/src/components/ObjectPage/ObjectPage.stories.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '@ui5/webcomponents-fiori/dist/illustrations/UnableToLoad.js';
22
import SampleImage from '@sb/demoImages/Person.png';
33
import type { Meta, StoryObj } from '@storybook/react';
4+
import { fn } from '@storybook/test';
45
import BarDesign from '@ui5/webcomponents/dist/types/BarDesign.js';
56
import ButtonDesign from '@ui5/webcomponents/dist/types/ButtonDesign.js';
67
import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
@@ -59,6 +60,7 @@ const meta = {
5960
imageShapeCircle: true,
6061
image: SampleImage,
6162
style: { height: '700px', maxHeight: '90vh' },
63+
onToggleHeaderArea: fn(),
6264
footerArea: (
6365
<Bar
6466
design={BarDesign.FloatingFooter}
@@ -73,7 +75,9 @@ const meta = {
7375
titleArea: (
7476
<ObjectPageTitle
7577
header={<Title level="H2">Denise Smith</Title>}
78+
snappedHeader={<Title level="H2">Denise Smith (snapped header)</Title>}
7679
subHeader="Senior UI Developer"
80+
snappedSubHeader={'Senior UI Developer (snapped header)'}
7781
actionsBar={
7882
<Toolbar design="Transparent">
7983
<ToolbarButton design={ButtonDesign.Emphasized} text="Primary Action" />

packages/main/src/components/ObjectPageTitle/ObjectPageTitle.cy.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,62 @@ describe('ObjectPageTitle', () => {
129129
cy.findByTestId('expandedContent').should('not.exist');
130130
});
131131
});
132+
133+
[
134+
{ snappedHeader: 'Snapped Header', header: 'Header' },
135+
{ snappedHeader: undefined, header: 'Header' },
136+
{ snappedHeader: undefined, header: undefined },
137+
{ snappedHeader: 'Snapped Header', header: undefined },
138+
].forEach(({ snappedHeader, header }) => {
139+
const titleParts = [];
140+
if (snappedHeader) {
141+
titleParts.push('snappedHeader');
142+
}
143+
if (header) {
144+
titleParts.push('header');
145+
}
146+
const title = titleParts.length ? titleParts.join(' & ') : 'no headers';
147+
148+
it(`renders with ${title}`, () => {
149+
cy.mount(
150+
<PageComponent
151+
childrenScrollable
152+
pageProps={{
153+
headerArea: (
154+
<ObjectPageHeader key="headerContent" style={{ height: '100px', background: 'lightblue' }}>
155+
Header Section
156+
</ObjectPageHeader>
157+
),
158+
style: { height: '800px' },
159+
}}
160+
titleProps={{
161+
snappedHeader,
162+
header,
163+
}}
164+
/>,
165+
);
166+
167+
// not snapped - always show header
168+
cy.findByText('Snapped Header').should('not.exist');
169+
if (header) {
170+
cy.findByText('Header').should('exist');
171+
} else {
172+
cy.findByText('Header').should('not.exist');
173+
}
174+
175+
cy.findByTestId('page').scrollTo('bottom');
176+
177+
// snapped - show snapped header if defined otherwise show header
178+
if (snappedHeader) {
179+
cy.findByText('Snapped Header').should('exist');
180+
cy.findByText('Header').should('not.exist');
181+
} else if (header) {
182+
cy.findByText('Snapped Header').should('not.exist');
183+
cy.findByText('Header').should('exist');
184+
} else {
185+
cy.findByText('Snapped Header').should('not.exist');
186+
cy.findByText('Header').should('not.exist');
187+
}
188+
});
189+
});
132190
});

packages/main/src/components/ObjectPageTitle/index.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const ObjectPageTitle = forwardRef<HTMLDivElement, ObjectPageTitlePropTypes>((pr
2828
onToggleHeaderContentVisibility,
2929
expandedContent,
3030
snappedContent,
31+
snappedHeader,
32+
snappedSubHeader,
3133
_snappedAvatar,
3234
...rest
3335
} = props as InternalProps;
@@ -41,6 +43,8 @@ const ObjectPageTitle = forwardRef<HTMLDivElement, ObjectPageTitlePropTypes>((pr
4143
);
4244
const containerClasses = clsx(classNames.container, isPhone && classNames.phone, className);
4345
const toolbarContainerRef = useRef<HTMLDivElement>(null);
46+
const _header = !props?.['data-header-content-visible'] && snappedHeader ? snappedHeader : header;
47+
const _subHeader = !props?.['data-header-content-visible'] && snappedSubHeader ? snappedSubHeader : subHeader;
4448

4549
useEffect(() => {
4650
isMounted.current = true;
@@ -157,9 +161,9 @@ const ObjectPageTitle = forwardRef<HTMLDivElement, ObjectPageTitlePropTypes>((pr
157161
data-component-name="ObjectPageTitleMiddleSection"
158162
>
159163
<FlexBox className={classNames.titleMainSection} onClick={onHeaderClick}>
160-
{header && (
164+
{_header && (
161165
<div className={classNames.title} data-component-name="ObjectPageTitleHeader">
162-
{header}
166+
{_header}
163167
</div>
164168
)}
165169
{children && (
@@ -182,13 +186,13 @@ const ObjectPageTitle = forwardRef<HTMLDivElement, ObjectPageTitlePropTypes>((pr
182186
</div>
183187
)}
184188
</FlexBox>
185-
{subHeader && (
189+
{_subHeader && (
186190
<FlexBox id="sub">
187191
<div
188192
className={clsx(classNames.subTitle, classNames.subTitleBottom)}
189193
data-component-name="ObjectPageTitleSubHeader"
190194
>
191-
{subHeader}
195+
{_subHeader}
192196
</div>
193197
</FlexBox>
194198
)}

packages/main/src/components/ObjectPageTitle/types/index.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,33 @@ export interface ObjectPageTitlePropTypes extends CommonProps {
2323
children?: ReactNode | ReactNode[];
2424

2525
/**
26-
* The `header` is positioned in the `ObjectPageTitle` left area.
27-
* Use this prop to display a `Title` (or any other component that serves as a heading).
26+
* The `header` is displayed in the left area of the `ObjectPageTitle`.
27+
* Use this prop to render a `Title` or any other component that serves as a heading.
28+
*
29+
* __Note:__ If the header is snapped (collapsed), the `snappedHeader` prop is used instead (if defined).
2830
*/
2931
header?: ReactNode;
3032
/**
31-
* The `subHeader` is positioned in the `ObjectPageTitle` left area below the `header`.
32-
* Use this aggregation to display a component like `Label` or any other component that serves as sub header.
33+
* The `snappedHeader` is displayed in the left area of the `ObjectPageTitle` when the header is snapped (collapsed).
34+
* Use this prop to render a `Title` or any other component that serves as a heading in the snapped view.
35+
*
36+
* @since 2.12.0
37+
*/
38+
snappedHeader?: ReactNode;
39+
/**
40+
* The `subHeader` is displayed in the left area of the `ObjectPageTitle`, below the `header`.
41+
* Use this prop to render a `Label` or any other component that serves as a sub-header.
42+
*
43+
* __Note:__ If the header is snapped (collapsed), the `snappedSubHeader` prop is used instead (if defined).
3344
*/
3445
subHeader?: ReactNode;
46+
/**
47+
* The `snappedSubHeader` is displayed in the left area of the `ObjectPageTitle` when the header is snapped (collapsed).
48+
* Use this prop to render a `Label` or any other component that serves as a sub-header in the snapped view.
49+
*
50+
* @since 2.12.0
51+
*/
52+
snappedSubHeader?: ReactNode;
3553
/**
3654
* Defines navigation-actions bar of the `ObjectPageTitle`.
3755
*

packages/main/src/components/VariantManagement/VariantManagement.cy.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,6 @@ describe('VariantManagement', () => {
393393
const [saved, setSaved] = useState(undefined);
394394
const handleSaveAs: VariantManagementPropTypes['onSaveAs'] = (e) => {
395395
onSaveAs(e);
396-
console.log(e.detail);
397396
const { variantItem: _0, children, global, isDefault, nativeDetail, selected, applyAutomatically } = e.detail;
398397
setSaved({ nativeDetail, selected, children, isDefault, global, applyAutomatically });
399398
};

0 commit comments

Comments
 (0)