<ui-input ddic-length="40" label="Functional Location Label"
value.bind="equipment.ES_SPECIFIC.READ_FLOC"
</ui-input>
<ui-input ddic-length="40" ddic-type="CHAR" label="Functional Location Label"
value.bind="equipment.ES_SPECIFIC.READ_FLOC"
shlp.bind="{type: 'SH', id: 'IFLM'}" mid="IFL">
</ui-input>
const express = require("express");
const ValueHelp = require("abap-value-help").ValueInputHelp;
const Client = require("abap-value-help").Client;
// Generic ABAP Value Help API used in prototyping system
const shlpApi = {
rfm_domvalues_get: "/COE/SHLP_DOMVALUES_GET",
rfm_metadata_get: "/COE/SHLP_METADATA_GET",
rfm_search: "/COE/SHLP_VALUES_GET",
};
const PORT = 3000;
const app = express();
let client;
let valueHelp;
app.use(express.json());
// Authenticate and open client connection
// Closed in /logout or automatically
app.route("/login").all(async (req, res) => {
try {
client = new Client(Object.keys(req.body).length > 0 ? req.body : { dest: "MME" });
await client.open();
const user = await client.call("BAPI_USER_GET_DETAIL", {
USERNAME: req.body.username || "DEMO",
});
// User parameters (SU3) passed to Value Helps handler
// make user defaults appear in Value Help web forms just like in SAPGUI
valueHelp = new ValueHelp(client, shlpApi, user.PARAMETER);
res.json("connected");
} catch (ex) {
res.json(ex.message);
}
});
// Fixed domain values
app.route("/fieldvalues").all(async (req, res) => {
if (!(client && client.alive)) {
return res.json("Do the login first");
}
const result = await valueHelp.getDomainValues(
Object.keys(req.body).length > 0 ? req.body : "RET_TYPE"
);
res.json(result);
});
// Complex/elementary Value Help descriptor (SH type)
// used to dynamically build the frontend Value Input dialog
app.route("/helpselect").all(async (req, res) => {
if (!(client && client.alive)) {
return res.json("Do the login first");
}
const descriptor = await valueHelp.getShlpDescriptor(
Object.keys(req.body).length > 0 ? req.body : { type: "SH", name: "CC_VBELN" }
);
res.json(descriptor);
});
// Run the search using selection parameters from Value Input Dialog
app.route("/search").all(async (req, res) => {
if (!(client && client.alive)) {
return res.json("Do the login first");
}
const shlpId = req.body.shlpId
? req.body.shlpId
: { type: "SH", name: "VMVAA" };
const selection = req.body.selection
? req.body.selection
: [
//["AUART", "I", "EQ", "OR", ""],
["BSTKD", "I", "EQ", "212345678", ""],
["VKORG", "I", "EQ", "1000", ""],
];
const result = await valueHelp.search(shlpId, selection);
res.json(result);
});
// Close the connection (optional)
app.route("/logout").all(async (req, res) => {
if (client && client.alive) await client.close();
res.json("disconnected");
});
app.listen(PORT, () =>
console.log(
"ABAP Value Help server ready:",
`\nhttp://localhost:${PORT}/login`,
`\nhttp://localhost:${PORT}/fieldvalues`,
`\nhttp://localhost:${PORT}/helpselect`,
`\nhttp://localhost:${PORT}/search`,
`\nhttp://localhost:${PORT}/logout`
)
);
gh repo clone SAP/fundamental-tools
cd abap-value-help/doc/server
npm install
node index
ABAP Value Help server ready:
http://localhost:3000/login
http://localhost:3000/fieldvalues
http://localhost:3000/helpselect
http://localhost:3000/search
http://localhost:3000/logout
<template>
<ai-dialog class="ui-search-help-dialog">
<ai-dialog-header>
<ui-row stretch>
<ui-combo options.bind="helpSelector" value.bind="shlpname" disabled.bind="helpSelectorDisabled"
select.delegate="selectHelp($event.detail.id)"></ui-combo>
</ui-row>
</ai-dialog-header>
<ai-dialog-body>
<!-- Search Parameters -->
<ui-row middle repeat.for="searchParam of searchParams" if.bind="!shlp.hide" class="ui-f4-param">
<ui-column size="md-4" class="ui-param-text">${searchParam.FIELDTEXT}</ui-column>
<ui-combo options.bind="helpSign" value.bind="searchParam.SIGN"></ui-combo>
<ui-combo options.bind="helpOption" value.bind="searchParam.OPTION"></ui-combo>
<ui-column fill>
<ui-input clear if.bind="searchParam.DATATYPE !== 'DATS' && searchParam.DATATYPE !== 'TIMS' "
id="${searchParam.FIELDNAME}_low" ddic-type="${searchParam.DATATYPE}"
ddic-length="${searchParam.LENG}" value.two-way="searchParam.LOW">
</ui-input>
<ui-input clear if.bind="searchParam.DATATYPE !== 'DATS' && searchParam.DATATYPE !== 'TIMS' "
show.bind="(searchParam.OPTION ==='BT') || (searchParam.OPTION ==='NB')"
id="${searchParam.FIELDNAME}_high" ddic-type="${searchParam.DATATYPE}"
ddic-length="${searchParam.LENG}" value.two-way="searchParam.HIGH">
</ui-input>
<ui-date clear if.bind="searchParam.DATATYPE === 'DATS' || searchParam.DATATYPE === 'TIMS' "
id="${searchParam.FIELDNAME}_low" ddic-type="${searchParam.DATATYPE}"
ddic-length="${searchParam.LENG}" date.two-way="searchParam.LOW">
</ui-date>
<ui-date clear if.bind="searchParam.DATATYPE === 'DATS' || searchParam.DATATYPE === 'TIMS' "
show.bind="(searchParam.OPTION ==='BT') || (searchParam.OPTION ==='NB')"
id="${searchParam.FIELDNAME}_high" ddic-type="${searchParam.DATATYPE}"
ddic-length="${searchParam.LENG}" date.two-way="searchParam.HIGH">
</ui-date>
</ui-column>
</ui-row>
<ui-row middle class="ui-f4-param">
<ui-column size="md-4" class="ui-param-text">Max. rows</ui-column>
<ui-input ddic-type="INT2" ddic-length="4" value.bind="maxRows"></ui-input>
</ui-column>
</ui-row>
<ui-row middle>
<ui-button reject click.delegate="cancel()" icon-suffix="sap-icon sap-icon-delete" label="Cancel">
</ui-button>
<ui-button default click.delegate="search()" icon-suffix="sap-icon sap-icon-search" label="Search">
</ui-button>
<ui-button accept click.delegate="confirm()" icon-suffix="sap-icon sap-icon-accept"
label="Confirm: ${selectedValue}" show.bind="selectedValue"></ui-button>
<!--ui-column auto class="ui-selected-value ui-pull-right">${selectedValue}</ui-column-->
<ui-column auto class="ui-pull-right" show.bind="searchResult.length">Found ${searchResult.length}
</ui-column>
</ui-row>
<!-- Search Result -->
<ui-row column class="ui-f4-result">
<ui-body scroll>
<ui-datagrid __title="${searchResult.length} records" selectable
rowselect.trigger="rowSelect($event)" empty-text="No records found" ref="__result">
</ui-datagrid>
</ui-body>
</ui-row>
</ai-dialog-body>
<ai-dialog-footer>
<ui-row>
</ui-row>
</ai-dialog-footer>
</ai-dialog>
</template>
import { DialogController } from 'aurelia-dialog';
import { UIApplication } from '../../utils/ui-application';
import { UIHttpService } from '../../utils/ui-http-service';
export class UISearchHelp {
searchParams = [];
searchResult = [];
helpSelector = [];
helpSelectorDisabled = false;
helpSign = [{ id: 'I', name: 'Include' }, { id: 'E', name: 'Exclude' }];
helpOption = [
{ id: 'EQ', name: 'is' },
{ id: 'NE', name: 'is not' },
{ id: 'GT', name: 'greater than' },
{ id: 'LT', name: 'less than' },
{ id: 'GE', name: 'not less' },
{ id: 'LE', name: 'not greater' },
{ id: 'BT', name: 'between' },
{ id: 'NB', name: 'not between' },
{ id: 'CP', name: 'with pattern' },
{ id: 'NP', name: 'w/o pattern' }
];
static inject = [UIApplication, UIHttpService, DialogController, Element];
constructor(app, httpService, controller, element) {
this.app = app;
this.userParams = this.app.User.params;
this.httpService = httpService;
this.controller = controller;
this.element = element;
}
activate(shlp) {
this.shlp = shlp;
// get the collective help list and open the first elementary help search form
this.httpService
.backend('/helpselect', shlp)
.then(FROM_ABAP => {
this.elementaryHelps = FROM_ABAP.elementary_helps;
// update help selection list
let helpList = [];
if (this.shlp.blacklist) this.shlp.blacklist = this.shlp.blacklist.toString();
else this.shlp.blacklist = '';
for (let shlpname of FROM_ABAP.sort_order) {
if (this.shlp.blacklist.indexOf(shlpname) !== -1) continue; // no no
helpList.push({ id: shlpname, name: this.elementaryHelps[shlpname].INTDESCR.DDTEXT });
}
this.helpSelector = helpList;
this.helpSelectorDisabled = helpList.length === 1;
if (this.shlp.autoselect) this.selectHelp(this.shlp.autoselect);
else this.selectHelp(helpList[0].id);
})
.catch(error => {
this.app.toastError(error);
});
}
clearSearchResult() {
this.selectedRow = [];
this.searchResult = [];
this.valueColumn = '';
this.selectedValue = null;
this.maxRowsExceeded = false;
}
selectHelp(shlpname = null) {
if (shlpname === null) return; // todo
this.maxRows = 500;
this.clearSearchResult();
//selected Help
this.shlpname = shlpname;
//if (Boolean(this.elementaryHelps[shlpname])) {
// this.shlptitle = this.elementaryHelps[shlpname].INTDESCR.DDTEXT;
//}
// set search params
this.searchParams = this.elementaryHelps[shlpname].FIELDDESCR;
for (let param of this.searchParams) {
if (this.shlp.selection && this.shlp.selection[param.FIELDNAME] !== undefined) {
param.PARVA = this.shlp.selection[param.FIELDNAME];
}
param.OPTION = 'EQ';
param.SIGN = 'I';
param.HIGH = '';
param.LOW = param.PARVA;
param.STYLE = {};
// param.STYLE.width = param.STYLE.width;
// FIXME: to takeover all user defaults, uncomment following check
if (param.MEMORYID && this.userParams) {
if (this.userParams[param.MEMORYID]) {
let midValue = this.userParams[param.MEMORYID].value;
param.LOW = midValue !== null ? midValue : '';
}
}
}
// console.log('elementary Params', this.shlpname, 'Params:', this.searchParams);
if (this.shlp.run) {
// autorun
// this.search(); todo
}
else {
setTimeout(() => {
let firstInput = this.element.querySelector('.ui-f4-param .ui-input-group:not(.ui-combo) input');
if (firstInput) firstInput.focus();
}, 200);
}
}
search() {
// init the result
this.clearSearchResult();
// prepare selection parameters
let selection = [];
let selectionLine = [];
for (let param of this.searchParams) {
selectionLine = [];
// console.log(i, this.searchParams[i]);
if (param.OPTION !== 'BT' && param.OPTION !== 'NB') {
if (param.LOW.length > 0) {
selectionLine.push(param.FIELDNAME);
selectionLine.push(param.SIGN);
selectionLine.push(param.OPTION);
selectionLine.push(param.LOW);
selectionLine.push('');
}
}
else if (param.LOW.length > 0 || param.HIGH.length > 0) {
selectionLine.push(param.FIELDNAME);
selectionLine.push(param.SIGN);
selectionLine.push(param.OPTION);
selectionLine.push(param.LOW);
selectionLine.push(param.HIGH);
}
if (selectionLine.length > 0) {
selection.push(selectionLine);
}
}
this.httpService
.backend('/search', {
shlpname: this.shlpname,
selection: selection,
maxrows: this.maxRows,
compact: false
})
.then(FROM_ABAP => {
this.maxRowsExceeded = isTrue(FROM_ABAP.maxrows_exceeded);
// result value column index (used in compact mode)
//for (let i = 0; i < this.Headers.length; i++) {
// if (this.Headers[i][0] === this.valueColumn) {
// this.valueColumnIndex = i;
// break;
// }
//}
// search result columns
let columns = [];
for (let h of FROM_ABAP.headers) {
let c = {
__title: h.title,
ddicType: h.abaptype,
dataLength: h.len,
dataId: h.field,
align: h.text_align,
__sortable: true
};
columns.push(c);
}
// search result data
this.searchResult = FROM_ABAP.search_result;
this.__result.__handle.refresh(columns, this.searchResult);
// output column
this.valueColumn = this.shlp.valueColumn || FROM_ABAP.shlpoutput;
})
.catch(error => {
this.app.toastError(error);
});
}
rowSelect(evt) {
this.selectedRow = evt.detail;
this.selectedValue = evt.detail[this.valueColumn];
}
cancel() {
this.controller.cancel();
}
confirm() {
let result = {
selectedValue: this.selectedValue,
selectedRow: this.selectedRow
};
if (this.shlp.textColumn) result.selectedText = this.selectedRow[this.shlp.textColumn];
this.controller.ok(result);
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
32 | |
24 | |
8 | |
7 | |
7 | |
6 | |
6 | |
6 | |
5 | |
4 |