Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .github/workflows/check-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ on:
types: [assigned, opened, synchronize, reopened, labeled, unlabeled]
branches:
- main

permissions:
contents: read
pull-requests: read

jobs:
Check-Changelog:
name: Check Changelog Action
Expand Down
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
save-exact=true
1 change: 1 addition & 0 deletions _i18n/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ INVALID_RECORD_KEY=Invalid key in recordKey: {0}
ERROR_RUNNING_DB_QUERY=Error running database query
INVALID_ELEMENT_IN_R_SELECT=Invalid element name supplied in r_select: {0}
INVALID_ELEMENT_IN_R_ORDERBY=Invalid element name supplied in r_orderby: {0}
INVALID_ELEMENT_IN_R_FILTER=Invalid element name supplied in r_filter: {0}
INVALID_R_FILTER_QUERY_PARAM=Invalid r_filter query parameter:
INVALID_TOP=$top must be a non-negative integer
INVALID_SKIP=$skip must be a non-negative integer
Expand Down
2,660 changes: 1,390 additions & 1,270 deletions app/data-inspector-ui/package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions app/data-inspector-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
],
"main": "webapp/index.html",
"devDependencies": {
"@ui5/cli": "^4.0.26",
"rimraf": "^6.0.1",
"ui5-task-zipper": "^3.4.4"
"@ui5/cli": "4.0.51",
"rimraf": "6.1.3",
"ui5-task-zipper": "3.6.0"
},
"ui5": {
"dependencies": [
Expand Down
2 changes: 1 addition & 1 deletion app/data-inspector-ui/webapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</style>
<script
id="sap-ui-bootstrap"
src="https://sapui5.hana.ondemand.com/1.143.2/resources/sap-ui-core.js"
src="https://sapui5.hana.ondemand.com/1.146.0/resources/sap-ui-core.js"
data-sap-ui-theme="sap_horizon"
data-sap-ui-resourceroots='{
"sap.cap.datainspector.datainspectorui": "./"
Expand Down
5 changes: 2 additions & 3 deletions app/data-inspector-ui/webapp/manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"_version": "1.65.0",
"_version": "2.6.0",
"sap.app": {
"id": "sap.cap.datainspector.datainspectorui",
"type": "application",
Expand Down Expand Up @@ -102,8 +102,7 @@
"type": "View",
"viewType": "XML",
"path": "sap.cap.datainspector.datainspectorui.view",
"async": true,
"viewPath": "sap.cap.datainspector.datainspectorui.view"
"async": true
},
"routes": [
{
Expand Down
4 changes: 2 additions & 2 deletions app/data-inspector-ui/webapp/test/flpSandbox.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@
</script>

<script
src="https://sapui5.hana.ondemand.com/1.139.0/test-resources/sap/ushell/bootstrap/sandbox.js"
src="https://sapui5.hana.ondemand.com/1.146.0/test-resources/sap/ushell/bootstrap/sandbox.js"
id="sap-ushell-bootstrap"
></script>
<!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions="allow"'' is a NON-SECURE setting for test environments -->
<script
id="sap-ui-bootstrap"
src="https://sapui5.hana.ondemand.com/1.139.0/resources/sap-ui-core.js"
src="https://sapui5.hana.ondemand.com/1.146.0/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m,sap.ui.core,sap.ushell"
data-sap-ui-async="true"
data-sap-ui-preload="async"
Expand Down
55 changes: 51 additions & 4 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,21 +1,68 @@
import cds from "@sap/cds/eslint.config.mjs";
import tseslint from "typescript-eslint";
import prettier from "eslint-config-prettier";

export default [
// Base CDS config (eslint:recommended + CDS globals + browser/test configs + ignores)
...cds,

// Global ignores for generated/build output
{
ignores: ["gen/", "templates/"],
},

// TypeScript files: parser + recommended rules
...tseslint.configs.recommended.map((config) => ({
...config,
files: ["**/*.ts"],
})),

// TypeScript source rules
{
files: ["**/*.ts"],
rules: {
"no-await-in-loop": "error",
"no-console": ["error", { allow: ["warn", "error"] }],
// Disable ESLint rules that typescript-eslint replaces
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/no-require-imports": "off", // cds-plugin.ts uses require()
// CDS types are incomplete — @ts-ignore/@ts-expect-error without descriptions is common
"@typescript-eslint/ban-ts-comment": [
"warn",
{
"ts-ignore": "allow-with-description",
"ts-expect-error": "allow-with-description",
minimumDescriptionLength: 0,
Comment thread
titanh3art marked this conversation as resolved.
},
],
// CDS/CAP APIs are often dynamically typed — warn instead of error
"@typescript-eslint/no-explicit-any": "warn",
},
},

// JavaScript source rules (for UI5 app controllers, etc.)
{
files: ["**/*.js"],
rules: {
"no-await-in-loop": "error",
"no-console": ["error", { allow: ["warn", "error"] }],
},
},

// Test overrides (relaxed rules) — note: directory is "test/", not "tests/"
{
files: ["tests/**"],
files: ["test/**"],
rules: {
"no-console": "off",
"no-undef": "off",
"no-unused-vars": "off",
"no-redeclare": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-explicit-any": "off",
// Chai assertions like `expect(...).to.be.true` are expressions
"@typescript-eslint/no-unused-expressions": "off",
},
},

// Prettier must be last to override conflicting formatting rules
prettier,
];
3 changes: 3 additions & 0 deletions lib/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ module.exports = class DataInspectorAddPlugin extends cds.add.Plugin {
];

async run() {
// Configurators must run sequentially as they may depend on each other's state
for (const configurator of this.configurators) {
// eslint-disable-next-line no-await-in-loop
if (await configurator.canRun()) {
log.debug(`Running ${configurator.name} configurator...`);
// eslint-disable-next-line no-await-in-loop
await configurator.run();
}
}
Expand Down
14 changes: 9 additions & 5 deletions lib/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ module.exports = class DataInspectorBuildPlugin extends cds.build.Plugin {
"data-inspector-ui"
);
if (!exists(uiAppSrc)) {
log.warn("Could not locate data-inspector UI5 app source, skipping build task");
log.warn(
"Could not locate data-inspector UI5 app source, skipping build task; See README for detail on build task"
);
return;
}

Expand All @@ -71,14 +73,14 @@ module.exports = class DataInspectorBuildPlugin extends cds.build.Plugin {
const destination = await this.resolveDestination();
if (destination !== DEFAULT_SRV_DESTINATION) {
await this.patchXsAppDestination(destination);
log.info(`Patched xs-app.json destination to '${destination}'`);
log.debug(`Patched xs-app.json destination to '${destination}'`);
}

// Patch manifest.json with sap.cloud.service when a value is available
const cloudService = await this.resolveCloudService();
if (cloudService) {
await this.patchManifestCloudService(cloudService);
log.info(`Patched manifest.json sap.cloud.service to '${cloudService}'`);
log.debug(`Patched manifest.json sap.cloud.service to '${cloudService}'`);
}
}

Expand Down Expand Up @@ -119,6 +121,8 @@ module.exports = class DataInspectorBuildPlugin extends cds.build.Plugin {
try {
const xsApp = JSON.parse(fs.readFileSync(xsAppPath, "utf8"));
const odataRoute = xsApp.routes?.find(
// xs-app.json routes have dynamic structure
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(r: any) => r.destination && (r.source?.includes("odata") || r.source?.includes("api"))
);
if (odataRoute?.destination) {
Expand All @@ -143,7 +147,7 @@ module.exports = class DataInspectorBuildPlugin extends cds.build.Plugin {
private async patchXsAppDestination(destination: string): Promise<void> {
const xsAppPath = join(this.task.dest, "xs-app.json");
if (!exists(xsAppPath)) {
log.warn("xs-app.json not found in build output, cannot patch destination");
log.debug("xs-app.json not found in build output, cannot patch destination");
return;
}

Expand Down Expand Up @@ -214,7 +218,7 @@ module.exports = class DataInspectorBuildPlugin extends cds.build.Plugin {
private async patchManifestCloudService(cloudService: string): Promise<void> {
const manifestPath = join(this.task.dest, "webapp", "manifest.json");
if (!exists(manifestPath)) {
log.warn("manifest.json not found in build output, cannot patch sap.cloud.service");
log.debug("manifest.json not found in build output, cannot patch sap.cloud.service");
return;
}

Expand Down
3 changes: 3 additions & 0 deletions lib/configurators/MtaConfigurator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export class MtaConfigurator extends AddPluginConfigurator {
}

const artifactExists = contentModule["build-parameters"].requires.some(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(req: any) => req.name === DATA_INSPECTOR_MTA_MODULE_NAME
);

Expand All @@ -104,6 +105,8 @@ export class MtaConfigurator extends AddPluginConfigurator {
* existing entries in the content module's build-parameters.requires.
* Falls back to "resources/" if no existing entry provides a target-path.
*/
// MTA build-parameters.requires has dynamic structure
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private resolveTargetPath(requires: any[]): string {
const DEFAULT_TARGET_PATH = "resources/";

Expand Down
6 changes: 5 additions & 1 deletion lib/configurators/PortalServiceConfigurator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ export class PortalServiceConfigurator extends AddPluginConfigurator {
log.debug("Added data inspector group to groupsOrder for default visibility");
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
log.error(`Failed to update groupsOrder: ${message}`);
log.error(
`Failed to update groupsOrder: ${message}` +
`To display the Data Inspector tile by default, manually add "${DATA_INSPECTOR_GROUP_ID}" ` +
`to the groupsOrder array in your preferred site.`
);
}
}

Expand Down
18 changes: 17 additions & 1 deletion lib/utils/mtaHelper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const cds = require("@sap/cds");
const { exists, read, write, path, yaml } = cds.utils;
const { exists, read, write, yaml } = cds.utils;
Comment thread
titanh3art marked this conversation as resolved.

const log = cds.log("data-inspector");

Expand All @@ -8,6 +8,8 @@ export function getMtaPath(): string | null {
return null;
}

// MTA YAML has dynamic structure - 'any' is appropriate for parsed content
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function readMta(): Promise<any | null> {
const mtaPath = getMtaPath();
if (!mtaPath) return null;
Expand All @@ -21,6 +23,8 @@ export async function readMta(): Promise<any | null> {
}
}

// MTA YAML has dynamic structure - 'any' is appropriate for parsed content
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function writeMta(mtaContent: any): Promise<void> {
const mtaPath = getMtaPath();
if (!mtaPath) return;
Expand All @@ -37,28 +41,34 @@ export async function writeMta(mtaContent: any): Promise<void> {
* 2. Return the first com.sap.application.content module whose requires
* array targets one of those resources with content-target: true.
*/
// MTA YAML has dynamic structure - 'any' is appropriate for parsed content
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function findContentModule(mtaContent: any): any | null {
const resources = mtaContent?.resources || [];
const modules = mtaContent?.modules || [];

const html5RepoHostNames = new Set(
resources
.filter(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(r: any) =>
r.type === "org.cloudfoundry.managed-service" &&
r.parameters?.service === "html5-apps-repo" &&
r.parameters?.["service-plan"] === "app-host"
)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.map((r: any) => r.name)
);

if (html5RepoHostNames.size === 0) return null;

return (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
modules.find((m: any) => {
if (m.type !== "com.sap.application.content") return false;
const requires = m.requires || [];
return requires.some(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(req: any) =>
html5RepoHostNames.has(req.name) && req.parameters?.["content-target"] === true
);
Expand All @@ -77,27 +87,33 @@ export function findContentModule(mtaContent: any): any | null {
*
* Returns the module's path (e.g. "flp") or null if not found.
*/
// MTA YAML has dynamic structure - 'any' is appropriate for parsed content
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function findPortalDeployerPath(mtaContent: any): string | null {
const resources = mtaContent?.resources || [];
const modules = mtaContent?.modules || [];

const portalResourceNames = new Set(
resources
.filter(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(r: any) =>
r.type === "org.cloudfoundry.managed-service" &&
r.parameters?.service === "portal" &&
r.parameters?.["service-plan"] === "standard"
)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.map((r: any) => r.name)
);

if (portalResourceNames.size === 0) return null;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const flpDeployer = modules.find((m: any) => {
if (m.type !== "com.sap.application.content") return false;
const requires = m.requires || [];
return requires.some(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(req: any) => portalResourceNames.has(req.name) && req.parameters?.["content-target"] === true
);
});
Expand Down
Loading
Loading