/*! * SAPUI5 * Copyright (c) 2025 SAP SE or an SAP affiliate company. All rights reserved. */ import Log from "sap/base/Log"; import type SearchModel from "sap/esh/search/ui/SearchModel"; import { ISearchTermHandler } from "./ISearchTermHandler"; // @ts-expect-error - module will be available during transpilation. Types are not available yet. import TCodeNavigation from "sap/ushell_abap/components/TCodeNavigation"; // @ts-expect-error - module will be available during transpilation. Types are not available yet. import Extension from "sap/ushell/api/performance/Extension"; // @ts-expect-error - module will be available during transpilation. Types are not available yet. import NavigationSource from "sap/ushell/api/performance/NavigationSource"; import i18n from "../i18n"; import { isCentralFioriLaunchpad } from "../SearchShellHelperCentralFioriLaunchpad"; interface TCodeNavigationErrorResultType extends Error { successful: boolean; messagecode: | "NAV_SUCCESS" | "NO_INBOUND_FOUND" | "UNKNOWN_ERROR" | "MANDATORY_PARAMETER_MISSING" | "DEFAULT_LADI_MISSING" | "DEFAULT_LADI_HAS_TILES_MISSING"; } interface TCodeNavigationType { /** * * @param sTcode sTCode The transaction code to search for, can also be an App ID. * @param bExplace Indicates whether to open the navigation in a new tab. * @returns A promise that resolves to a boolean indicating the success of the navigation. */ navigateByTCode(sTcode: string, bExplace: boolean): Promise; } export default class TransactionsHandler implements ISearchTermHandler { private logger = Log.getLogger("sap.esh.search.ui.searchtermhandler.TransactionsHandler"); constructor(private readonly searchModel: SearchModel) {} private logNavigationEvent(): void { try { const extension = new Extension(); extension.addNavigationSource(NavigationSource.SearchCEP); } catch (e) { this.logger.error("Error logging navigation event for TCode", e as Error); } } private handleTCodeError(error: TCodeNavigationErrorResultType): void { let message = i18n.getText("error.TCodeUnknownError.message"); let solution = i18n.getText("error.TCodeUnknownError.solution"); switch (error?.messagecode) { case "MANDATORY_PARAMETER_MISSING": message = i18n.getText("error.TCodeMandatoryParameterMissingError.message"); solution = i18n.getText("error.TCodeMandatoryParameterMissingError.solution"); break; case "NO_INBOUND_FOUND": message = i18n.getText("error.TCodeNotFoundError.message"); solution = i18n.getText("error.TCodeNotFoundError.solution"); break; case "DEFAULT_LADI_MISSING": message = i18n.getText("error.TCodeDefaultLadiMissing.message"); solution = i18n.getText("error.TCodeDefaultLadiMissing.solution"); break; case "DEFAULT_LADI_HAS_TILES_MISSING": message = i18n.getText("error.TCodeLadiHasTilesMissing.message"); solution = i18n.getText("error.TCodeLadiHasTilesMissing.solution"); break; } if (this.searchModel.config.FF_useWebComponentsSearchInput) { // web component error handling this.searchModel.setProperty("/illustratedMessage", [ { titleText: message, subtitleText: solution, illustrationName: "UnableToUpload", buttonText: i18n.getText("error.TCodeShowMoreInformation.solution"), url: "https://me.sap.com/notes/3687260", }, ]); } else { // fake some app suggestions for the error message: this.searchModel.setProperty("/suggestions", [ { icon: "sap-icon://error", label: message, uiSuggestionType: "App", }, { icon: "sap-icon://hint", label: solution, uiSuggestionType: "App", url: "https://me.sap.com/notes/3687260", }, ]); } } handleSearchTerm(searchTerm: string): Promise | void { if (isCentralFioriLaunchpad()) { // no transaction handling in cFLP/multiprovider return; } let explace; // replace current app: if (searchTerm.toLowerCase().indexOf("/n") === 0) { explace = false; } // open in new window (explace): if (searchTerm.toLowerCase().indexOf("/o") === 0) { explace = true; } if (typeof explace !== "undefined") { this.searchModel.setProperty("/suggestions", []); let tCode = searchTerm.slice(2); tCode = tCode.trim(); this.logNavigationEvent(); return (TCodeNavigation as TCodeNavigationType) .navigateByTCode(tCode, explace) .then(() => { this.searchModel.setSearchBoxTerm("", false); }) .catch((error: TCodeNavigationErrorResultType) => { this.handleTCodeError(error); throw error; }); } } }