Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
03018f8
feat: add sap-anchor-bar-visible eslint rule
marcovieth Jan 23, 2026
6de7461
Linting auto fix commit
github-actions[bot] Jan 23, 2026
22d56f9
Merge remote-tracking branch 'origin/main' into feat/rule-anchorBarVi…
marcovieth Feb 17, 2026
f4fb43c
Merge branch 'feat/rule-anchorBarVisible' of https://github.com/SAP/o…
marcovieth Feb 17, 2026
155cde9
feat(eslint): add auto-fix capability to sap-anchor-bar-visible rule
marcovieth Feb 17, 2026
25f17de
feat(eslint): refine sap-anchor-bar-visible rule to check false value…
marcovieth Feb 18, 2026
4342688
feat: add exception for Form Entry Object Pages in sap-anchor-bar-vis…
marcovieth Feb 19, 2026
d4e6232
chore: add changeset
marcovieth Feb 19, 2026
77ae06d
Merge branch 'main' into feat/rule-anchorBarVisible
marcovieth Feb 19, 2026
b3cb341
test: remove redundant test case for header without anchorBarVisible
marcovieth Feb 23, 2026
7b74c9b
Merge branch 'main' into feat/rule-anchorBarVisible
marcovieth Feb 23, 2026
7b77491
docs: update sap-anchor-bar-visible rule documentation and messaging
marcovieth Feb 24, 2026
236c959
Merge branch 'main' into feat/rule-anchorBarVisible
marcovieth Feb 24, 2026
b00ab99
docs: clarify anchorBarVisible rule documentation
marcovieth Feb 25, 2026
524b461
Merge branch 'main' into feat/rule-anchorBarVisible
Klaus-Keller Feb 25, 2026
9472d54
refactor: Implement header config extraction in fe-v4 linkerpage head…
marcovieth Mar 2, 2026
8abba72
refactor: standardize object page header configuration with Configura…
marcovieth Mar 3, 2026
22911a0
Merge branch 'main' into feat/rule-anchorBarVisible
marcovieth Mar 3, 2026
d19b457
fix: initial eslint 10
marufrasully Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/eighty-keys-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
'@sap-ux/eslint-plugin-fiori-tools': minor
---
Add sap-anchor-bar-visible eslint rule.
1 change: 1 addition & 0 deletions packages/eslint-plugin-fiori-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export default [

| Rule | Description | Recommended | Recommended for S/4HANA |
|------|-------------|:-----------:|:-----------------------:|
| [sap-anchor-bar-visible](docs/rules/sap-anchor-bar-visible.md) | Anchor Bar Visible should not be set to false in manifest settings for object page headers (except form entry object pages). | | ✅ |
| [sap-bookmark-performance](docs/rules/sap-bookmark-performance.md) | Ensure the correct usage of the auto-refresh interval options for `sap.ushell.ui.footerbar.AddBookmarkButton`. | ✅ | ✅ |
| [sap-browser-api-error](docs/rules/sap-browser-api-error.md) | Detect forbidden usages of `(window.)document` APIs. | | |
| [sap-browser-api-warning](docs/rules/sap-browser-api-warning.md) | Detect warnings for usages of `(window.)document` APIs. | ✅ | ✅ |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Disallow Setting `anchorBarVisible` to `false` in Object Page Headers (`sap-anchor-bar-visible`)

Ensures that the `anchorBarVisible` property is not set to `false` in the object page header configuration in the `manifest.json` file.

## Rule Details

This rule checks if the `anchorBarVisible` property is set to `false` in the object page header configuration within the `manifest.json` file. We recommend that you don't set this property to `false`, as it impacts the user experience and navigation within object pages.

### Why Was This Rule Introduced?

The anchor bar is an important navigation feature in object pages that enables users to quickly jump between different sections. Setting `anchorBarVisible` to `false` in the `manifest.json` file can negatively impact user experience. This rule ensures the correct configuration of object page headers.

### Warning Message

The following patterns are considered warnings:

#### Incorrect Manifest Configuration

```json
{
"sap.ui5": {
"routing": {
"targets": {
"MyObjectPage": {
"options": {
"settings": {
"content": {
"header": {
"anchorBarVisible": false
}
}
}
}
}
}
}
}
}
```

The `anchorBarVisible` property is set to `false`, which is not recommended.

The following patterns are considered correct:

#### Correct Manifest Configuration (Property Set to `true`)

```json
{
"sap.ui5": {
"routing": {
"targets": {
"MyObjectPage": {
"options": {
"settings": {
"content": {
"header": {
"anchorBarVisible": true
}
}
}
}
}
}
}
}
}
```

The `anchorBarVisible` property is set to `true`, which is the recommended setting.

#### Correct Manifest Configuration (Property Not Set)

```json
{
"sap.ui5": {
"routing": {
"targets": {
"MyObjectPage": {
"options": {
"settings": {
"content": {
"header": {}
}
}
}
}
}
}
}
}
```

The `anchorBarVisible` property is not configured, which is also acceptable.

#### Correct Manifest Configuration (Form Entry Object Page)

```json
{
"sap.ui5": {
"routing": {
"targets": {
"FormEntryObjectPage": {
"options": {
"settings": {
"content": {
"header": {
"visible": false,
"anchorBarVisible": false
}
}
}
}
}
}
}
}
}
```

Form entry object pages are allowed to have both `visible: false` and `anchorBarVisible: false`, as this is the recommended pattern for data entry pages.

## How to Fix

To fix the warning, either remove the `anchorBarVisible` property entirely or set it to `true`. The rule provides an automatic fix that removes the property when it's set to `false`.

## Bug Report

If you encounter an issue with this rule, please open a [GitHub issue](https://github.com/SAP/open-ux-tools/issues).

## Further Reading

- [UI5 Form Entry Object Page](https://ui5.sap.com/#/topic/533f7e7f59854cb08ce8074814ae83c5)
2 changes: 1 addition & 1 deletion packages/eslint-plugin-fiori-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"devDependencies": {
"c8": "^10.1.3",
"cross-env": "7.0.3",
"eslint": "^9",
"eslint": "^10",
"@typescript-eslint/rule-tester": "8.46.2",
"eslint-plugin-eslint-plugin": "7.2.0"
},
Expand Down
7 changes: 4 additions & 3 deletions packages/eslint-plugin-fiori-tools/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const plugin: Plugin = {
namespace: '@sap-ux/fiori-tools'
},
languages,
rules: rules as Plugin['rules'],
rules: rules as unknown as Plugin['rules'],
processors: {}
};

Expand Down Expand Up @@ -237,7 +237,7 @@ export const configs: Record<string, Linter.Config[]> = {
plugins: {
'@sap-ux/fiori-tools': {
meta,
rules
rules: rules as unknown as Plugin['rules']
}
}
},
Expand All @@ -253,7 +253,7 @@ export const configs: Record<string, Linter.Config[]> = {
'@sap-ux/fiori-tools': {
meta,
languages,
rules
rules: rules as unknown as Plugin['rules']
}
}
},
Expand All @@ -265,6 +265,7 @@ export const configs: Record<string, Linter.Config[]> = {
files: ['**/manifest.json', '**/*.xml', '**/*.cds'],
language: '@sap-ux/fiori-tools/fiori',
rules: {
'@sap-ux/fiori-tools/sap-anchor-bar-visible': 'warn',
'@sap-ux/fiori-tools/sap-flex-enabled': 'warn',
'@sap-ux/fiori-tools/sap-width-including-column-header': 'warn',
'@sap-ux/fiori-tools/sap-copy-to-clipboard': 'warn',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Manifest } from '@sap-ux/project-access';
import type { AnnotationReference } from '../project-context/parser';
export const WIDTH_INCLUDING_COLUMN_HEADER_RULE_TYPE = 'sap-width-including-column-header';
export const ANCHOR_BAR_VISIBLE = 'sap-anchor-bar-visible';
export const FLEX_ENABLED = 'sap-flex-enabled';
export const COPY_TO_CLIPBOARD = 'sap-copy-to-clipboard';
export const ENABLE_EXPORT = 'sap-enable-export';
Expand All @@ -19,7 +20,11 @@ export interface WidthIncludingColumnHeaderDiagnostic {
reference: AnnotationReference;
};
}

export interface AnchorBarVisible {
type: typeof ANCHOR_BAR_VISIBLE;
pageName: string;
manifest: ManifestPropertyDiagnosticData;
}
export interface ManifestPropertyDiagnosticData {
uri: string;
object: Manifest;
Expand Down Expand Up @@ -86,6 +91,7 @@ export interface TableColumnVerticalAlignment {

export type Diagnostic =
| WidthIncludingColumnHeaderDiagnostic
| AnchorBarVisible
| FlexEnabled
| CopyToClipboard
| CreationModeForTable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { MetadataElement } from '@sap-ux/odata-annotation-core';
import type { ParsedService } from '../parser';
import type { LinkerContext, ConfigurationBase } from './types';
import type { LinkerContext, ConfigurationBase, ConfigurationProperty } from './types';
import { getParsedServiceByName } from '../utils';
import type { AnnotationNode, TableNode, TableSectionNode } from './annotations';
import { collectTables, collectSections } from './annotations';
Expand Down Expand Up @@ -30,6 +30,10 @@ export interface FeV4ObjectPage extends ConfigurationBase<'object-page'> {
entity: MetadataElement;
sections: Section[];
lookup: NodeLookup<Table | Section>;
header: {
anchorBarVisible: ConfigurationProperty<boolean>;
visible: ConfigurationProperty<boolean>;
};
}

export type FeV4PageType = FeV4ListReport | FeV4ObjectPage;
Expand Down Expand Up @@ -227,9 +231,20 @@ export function runFeV4Linker(context: LinkerContext): LinkedFeV4App {
entity: entity,
configuration: {},
sections: [],
lookup: {}
lookup: {},
header: {
anchorBarVisible: {
values: [true, false],
configurationPath: []
},
visible: {
values: [true, false],
configurationPath: []
}
}
};
linkObjectPageSections(page, path, name, sections, target);
linkObjectPageHeader(page, target);
linkedApp.pages.push(page);
}
}
Expand All @@ -243,6 +258,12 @@ interface Target {
contextPath?: string;

controlConfiguration?: { [key: string]: TableConfiguration };
content?: {
header?: {
anchorBarVisible?: boolean;
visible?: boolean;
};
};
};
};
}
Expand Down Expand Up @@ -457,6 +478,23 @@ function linkObjectPageSections(
}
}

/**
* Links the object page header configuration for Fiori Elements V4.
*
* @param page - The object page being linked
* @param target - The routing target containing the header configuration
*/
function linkObjectPageHeader(page: FeV4ObjectPage, target: Target): void {
const header = target.options?.settings?.content?.header;
const basePath = ['sap.ui5', 'routing', 'targets', page.targetName, 'options', 'settings', 'content', 'header'];

page.header.anchorBarVisible.valueInFile = header?.anchorBarVisible;
page.header.anchorBarVisible.configurationPath = [...basePath, 'anchorBarVisible'];

page.header.visible.valueInFile = header?.visible;
page.header.visible.configurationPath = [...basePath, 'visible'];
}

interface PageSettings {
contextPath?: string;
entitySet?: string;
Expand Down
3 changes: 3 additions & 0 deletions packages/eslint-plugin-fiori-tools/src/rules/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { FioriRuleDefinition } from '../types';
import type { FioriXMLRuleDefinition } from '../language/xml/types';
import {
ANCHOR_BAR_VISIBLE,
FLEX_ENABLED,
WIDTH_INCLUDING_COLUMN_HEADER_RULE_TYPE,
COPY_TO_CLIPBOARD,
Expand Down Expand Up @@ -61,6 +62,7 @@ import sapUi5LegacyJquerysapUsage from './sap-ui5-legacy-jquerysap-usage';
import sapUi5NoPrivateProp from './sap-ui5-no-private-prop';
import sapUsageBasemastercontroller from './sap-usage-basemastercontroller';

import anchorBarVisibleRule from './sap-anchor-bar-visible';
import flexEnabledRule from './sap-flex-enabled';
import requireWidthIncludingColumnHeader from './sap-width-including-column-header';
import creationModeForTable from './sap-creation-mode-for-table';
Expand Down Expand Up @@ -121,6 +123,7 @@ export const rules: Record<string, Rule.RuleModule | FioriRuleDefinition | Fiori
'sap-ui5-legacy-jquerysap-usage': sapUi5LegacyJquerysapUsage,
'sap-ui5-no-private-prop': sapUi5NoPrivateProp,
'sap-usage-basemastercontroller': sapUsageBasemastercontroller,
[ANCHOR_BAR_VISIBLE]: anchorBarVisibleRule,
[FLEX_ENABLED]: flexEnabledRule,
[WIDTH_INCLUDING_COLUMN_HEADER_RULE_TYPE]: requireWidthIncludingColumnHeader,
[COPY_TO_CLIPBOARD]: copyToClipboard,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type { FioriRuleDefinition } from '../types';
import { ANCHOR_BAR_VISIBLE, type AnchorBarVisible } from '../language/diagnostics';
import { createFioriRule } from '../language/rule-factory';
import type { MemberNode } from '@humanwhocodes/momoa';
import { createJsonFixer } from '../language/rule-fixer';

const rule: FioriRuleDefinition = createFioriRule({
ruleId: ANCHOR_BAR_VISIBLE,
meta: {
type: 'suggestion',
docs: {
recommended: true,
description:
'Anchor Bar Visible should not be set to false in manifest settings for object page headers (except form entry object pages)',
url: 'https://github.com/SAP/open-ux-tools/blob/main/packages/eslint-plugin-fiori-tools/docs/rules/sap-anchor-bar-visible.md'
},
messages: {
[ANCHOR_BAR_VISIBLE]:
'The "anchorBarVisible" property should not be set to false in manifest settings. Remove this property from the object page header configuration. Exception: Form entry object pages can have both "visible" and "anchorBarVisible" set to false.'
},
fixable: 'code'
},

check(context) {
const problems: AnchorBarVisible[] = [];

for (const [appKey, app] of Object.entries(context.sourceCode.projectContext.linkedModel.apps)) {
if (app.type !== 'fe-v4') {
continue;
}
for (const page of app.pages) {
if (page.type !== 'object-page') {
continue;
}
const parsedApp = context.sourceCode.projectContext.index.apps[appKey];

// Check if anchorBarVisible is set to false
// Exception: Form Entry Object Pages can have both visible: false and anchorBarVisible: false
const anchorBarVisible = page.header.anchorBarVisible.valueInFile;
const headerVisible = page.header.visible.valueInFile;

if (anchorBarVisible === false && headerVisible !== false) {
problems.push({
type: ANCHOR_BAR_VISIBLE,
pageName: page.targetName,
manifest: {
uri: parsedApp.manifest.manifestUri,
object: parsedApp.manifestObject,
propertyPath: page.header.anchorBarVisible.configurationPath
}
});
}
}
}

return problems;
},
createJsonVisitorHandler: (context, diagnostic, deepestPathResult) =>
function report(node: MemberNode): void {
context.report({
node,
messageId: ANCHOR_BAR_VISIBLE,
fix: createJsonFixer({
context,
deepestPathResult,
node,
operation: 'delete'
})
});
}
});

export default rule;
Loading
Loading