Add the search page
The search page is an ordinary Fluid component with a search box, a summary of how the question was understood, and the results. All of its work happens in PeopleCode on the application server, through the search application class, so the browser never talks to the NL Search Service.
What you’ll create
Section titled “What you’ll create”| Definition | What it’s for |
|---|---|
ZZ_NLS_WRK |
Derived record: the question, the stored plan, the summary label, the count |
ZZ_NLS_FILTER |
Derived record: one row per part of the summary, with a remove button |
ZZ_NLS_RESULT |
Derived record: one row per result, with its title, summary, and link |
ZZ_NL_SEARCH |
The Fluid page, and the component that holds it |
ZZ_NLSEARCH |
The menu the component is registered on |
Build the page
Section titled “Build the page”-
Create the derived records.
ZZ_NLS_WRK, withZZ_QUESTION, a 254-character field;ZZ_SEARCH, for the Search button;ZZ_LABELandZZ_HITS, to show the summary label and the result count; andZZ_PLAN, a long character field that holds the service’s response between requests.ZZ_NLS_FILTER, withZZ_NUM,ZZ_TEXT, andZZ_ACTIVE, andZZ_REMOVE, for its remove button.ZZ_NLS_RESULT, withZZ_TITLE,ZZ_SUMMARY, andZZ_URL, andZZ_OPEN, for its open button.
-
Create the Fluid page,
ZZ_NL_SEARCH. At level 0, put the search box,ZZ_QUESTION, with the Search button beside it, and thenZZ_LABELandZZ_HITS. Below them, add two grids: one forZZ_NLS_FILTER, laid out as a row of filters, each with its remove button, and one forZZ_NLS_RESULT, as a list of results. KeepZZ_PLAN,ZZ_NUM,ZZ_ACTIVE, andZZ_URLhidden. -
Create the component. Add the page to a new component,
ZZ_NL_SEARCH. On the Fluid tab of the component properties, select Fluid Mode, and useINSTALLATIONas the search record, since the component has no keys. -
Add the PeopleCode below.
Add the PeopleCode
Section titled “Add the PeopleCode”Show the results
Section titled “Show the results”One function runs the stored plan, leaving out the filters the user removed, and fills the results
grid. Save it as FieldFormula PeopleCode on ZZ_NLS_WRK.ZZ_HITS, so that each button can call it:
import ZZ_NLSEARCH:Search;import PT_SEARCH:*;
Function ZZ_NLS_Show() Local JsonObject &plan; Local JsonParser &parser = CreateJsonParser(); If All(ZZ_NLS_WRK.ZZ_PLAN) Then If &parser.Parse(ZZ_NLS_WRK.ZZ_PLAN) Then &plan = &parser.GetRootObject(); End-If; End-If;
/* The filters the user removed from the summary */ Local Rowset &filters, &grid; Local array of number &removed = CreateArrayRept(0, 0); Local integer &i; &filters = GetLevel0()(1).GetRowset(Scroll.ZZ_NLS_FILTER); For &i = 1 To &filters.ActiveRowCount If &filters(&i).ZZ_NLS_FILTER.ZZ_ACTIVE.Value = "N" Then &removed.Push(&filters(&i).ZZ_NLS_FILTER.ZZ_NUM.Value); End-If; End-For;
/* Run the search, and fill the results grid */ Local ZZ_NLSEARCH:Search &nls = create ZZ_NLSEARCH:Search(); Local PT_SEARCH:SearchResultCollection &results; Local PT_SEARCH:SearchResult &result; Local Record &rec; Local string &q = ZZ_NLS_WRK.ZZ_QUESTION; &results = &nls.Run(&plan, &q, &removed, 1, 50);
&grid = GetLevel0()(1).GetRowset(Scroll.ZZ_NLS_RESULT); &grid.Flush(); For &i = 1 To &results.GetDocumentCount() If &i > 1 Then &grid.InsertRow(&i - 1); End-If; &result = &results.Item(&i); &rec = &grid(&i).ZZ_NLS_RESULT; &rec.ZZ_TITLE.Value = &result.GetTitle(); &rec.ZZ_SUMMARY.Value = &result.GetSummary(); &rec.ZZ_URL.Value = &result.GetUrlLink(); End-For; ZZ_NLS_WRK.ZZ_HITS = &results.GetEstimatedHitCount();End-Function;The Search button
Section titled “The Search button”The Search button asks for a plan, keeps it, fills the summary with one removable filter for each of its parts, and shows the results:
import ZZ_NLSEARCH:Search;Declare Function ZZ_NLS_Show PeopleCode ZZ_NLS_WRK.ZZ_HITS FieldFormula;
Local ZZ_NLSEARCH:Search &nls = create ZZ_NLSEARCH:Search();Local JsonObject &plan = &nls.Plan(ZZ_NLS_WRK.ZZ_QUESTION);Local JsonObject &summary;Local JsonArray &parts;Local Rowset &filters;Local Record &rec;Local integer &i;
/* Keep the plan, so removing a filter needs no new plan */ZZ_NLS_WRK.ZZ_PLAN = "";ZZ_NLS_WRK.ZZ_LABEL = "";&filters = GetLevel0()(1).GetRowset(Scroll.ZZ_NLS_FILTER);&filters.Flush();
If &plan <> Null Then ZZ_NLS_WRK.ZZ_PLAN = &plan.ToString(); /* Log the request ID with %UserId here, in ZZ_NLS_LOG */ If Not &plan.IsNullProperty("intent") Then &summary = &plan.GetJsonObject("summary"); &parts = &summary.GetJsonArray("filters"); ZZ_NLS_WRK.ZZ_LABEL = &summary.GetString("label"); For &i = 1 To &parts.Length() If &i > 1 Then &filters.InsertRow(&i - 1); End-If; &rec = &filters(&i).ZZ_NLS_FILTER; &rec.ZZ_NUM.Value = &i; &rec.ZZ_TEXT.Value = &parts.GetString(&i); &rec.ZZ_ACTIVE.Value = "Y"; End-For; End-If;End-If;
ZZ_NLS_Show();When there’s no plan, the summary stays empty, and ZZ_NLS_Show runs a keyword search with the
question as typed.
Removing a filter and opening a result
Section titled “Removing a filter and opening a result”The remove button hides its filter, and shows the results again from the stored plan, without asking the service for a new one:
Declare Function ZZ_NLS_Show PeopleCode ZZ_NLS_WRK.ZZ_HITS FieldFormula;
GetRow().ZZ_NLS_FILTER.ZZ_ACTIVE.Value = "N";GetRow().Visible = False;ZZ_NLS_Show();The open button opens the result’s page:
/* Open the result; its page checks the user's access again */ViewURL(GetRow().ZZ_NLS_RESULT.ZZ_URL.Value);Register it and add a tile
Section titled “Register it and add a tile”-
Register the component. With the component open in Application Designer, choose Register Component to start the registration wizard. Add it to the
ZZ_NLSEARCHmenu, create its content reference in the Fluid Structure Content folder, and add it to the permission listZZ_NLS_USER. -
Create a tile. At PeopleTools > Portal > Tile Wizard, create a tile for the component, named Search in plain language, and add it to the homepages of the people who search vouchers, and to the NavBar.
Try it
Section titled “Try it”Sign in as a test user with ZZ_NLS_USER, open the tile, and search for “Vouchers over $10,000
from Acme entered last month”. The summary reads Vouchers · Supplier: Acme · Amount: over
10,000 · Entered: 1–31 August 2026, and the results are Acme’s vouchers from the test user’s
business units only. Remove the amount filter, and the results widen to all of Acme’s vouchers
from last month in those business units, straight away, with no new call to the service.
