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
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.Phone
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.RadioButtons
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.Region
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.RichText
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.SemanticLink
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.RootContainer
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.SimpleComboBox
import com.pega.constellation.sdk.kmp.core.components.ComponentTypes.SimpleTable
Expand Down Expand Up @@ -71,6 +72,7 @@ import com.pega.constellation.sdk.kmp.core.components.fields.PhoneComponent
import com.pega.constellation.sdk.kmp.core.components.fields.RadioButtonsComponent
import com.pega.constellation.sdk.kmp.core.components.fields.RichTextComponent
import com.pega.constellation.sdk.kmp.core.components.fields.SimpleComboBoxComponent
import com.pega.constellation.sdk.kmp.core.components.fields.SemanticLinkComponent
import com.pega.constellation.sdk.kmp.core.components.fields.TextAreaComponent
import com.pega.constellation.sdk.kmp.core.components.fields.TextInputComponent
import com.pega.constellation.sdk.kmp.core.components.fields.TimeComponent
Expand Down Expand Up @@ -118,6 +120,7 @@ object ComponentRegistry {
Def(RadioButtons) { RadioButtonsComponent(it) },
Def(Region) { RegionComponent(it) },
Def(RootContainer) { RootContainerComponent(it) },
Def(SemanticLink) { SemanticLinkComponent(it) },
Def(SimpleTable) { SimpleTableComponent(it) },
Def(SimpleTableManual) { SimpleTableManualComponent(it) },
Def(SimpleTableSelect) { SimpleTableSelectComponent(it) },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ object ComponentTypes {
val RadioButtons = ComponentType("RadioButtons")
val RichText = ComponentType("RichText")
val SimpleComboBox = ComponentType("SimpleComboBox")
val SemanticLink = ComponentType("SemanticLink")
val TextArea = ComponentType("TextArea")
val TextInput = ComponentType("TextInput")
val Time = ComponentType("Time")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.pega.constellation.sdk.kmp.core.components.fields

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.pega.constellation.sdk.kmp.core.api.BaseComponent
import com.pega.constellation.sdk.kmp.core.api.ComponentContext
import com.pega.constellation.sdk.kmp.core.api.HideableComponent
import com.pega.constellation.sdk.kmp.core.components.getString
import com.pega.constellation.sdk.kmp.core.components.optBoolean
import kotlinx.serialization.json.JsonObject

class SemanticLinkComponent(context: ComponentContext) : BaseComponent(context), HideableComponent {
var value: String by mutableStateOf("")
private set
var label: String by mutableStateOf("")
private set
override var visible: Boolean by mutableStateOf(false)
private set

override fun applyProps(props: JsonObject) {
with(props) {
value = getString("value")
label = getString("label")
visible = optBoolean("visible", true)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.pega.constellation.sdk.kmp.samples.androidcmpapp.test.cases

import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import com.pega.constellation.sdk.kmp.samples.androidcmpapp.test.ComposeTest
import com.pega.constellation.sdk.kmp.samples.androidcmpapp.test.runAndroidTest
import com.pega.constellation.sdk.kmp.samples.androidcmpapp.test.waitForNode
import com.pega.constellation.sdk.kmp.samples.androidcmpapp.test.waitForNodes
import com.pega.constellation.sdk.kmp.test.mock.PegaVersion
import kotlin.test.Test

@OptIn(ExperimentalTestApi::class)
class DataRefSemanticLinkTest : ComposeTest(PegaVersion.v25_1) {

@Test
fun test_data_reference_form_and_semantic_link() = runAndroidTest {
setupApp("OI1OYV-Marco2-Work-DataReferenceTest-FieldOnly")

// create case
onNodeWithText("New Service").performClick()

// Step 1: verify DataReference form with Dropdown appears
waitForNode("DataReferenceSingleCars")

// Select "Focus" from the dropdown
onNodeWithText("DataReferenceSingleCars").performClick()
waitForNode("Focus")
onNodeWithText("Focus").performClick()

// Verify refresh populated the subview with Brand and Model
waitForNodes("Focus", 2)
waitForNode("Ford")

// Submit step 1 → step 2 loads with SemanticLink
onNodeWithText("Next").performClick()

// Step 2: verify SemanticLink renders the selected car model
waitForNode("Focus")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -279,26 +279,38 @@ export class DataReferenceComponent extends ContainerBaseComponent {
#handleSelection(event) {
const caseKey = this.pConn.getCaseInfo().getKey();
const refreshOptions = { autoDetectRefresh: true };
// AutoComplete sets value on event.id whereas Dropdown sets it on event.target.value
const selectionValue = event?.id || event?.target?.value;

const children = this.pConn.getRawMetadata()?.children;
if (children?.length > 0 && children[0].config?.value) {
refreshOptions.propertyName = children[0].config.value;
refreshOptions.classID = this.pConn.getRawMetadata().classID;
}

// Skip manual refreshCaseView for picklist-based children (Dropdown, AutoComplete, Checkbox)
// as they don't have an associated view configured and trigger refresh automatically
const hasAssociatedViewConfigured = this.rawViewMetadata.children?.[1]?.children?.length;

if (this.canBeChangedInReviewMode && this.pConn.getValue("__currentPageTabViewName")) {
this.pConn
.getActionsApi()
.refreshCaseView(caseKey, this.pConn.getValue("__currentPageTabViewName"), "", refreshOptions);
.refreshCaseView(caseKey, this.pConn.getValue("__currentPageTabViewName"), "", refreshOptions)
?.catch((error) => {
console.warn(`${TAG} refreshCaseView failed (review mode)`, error?.name, error?.message);
});
PCore.getDeferLoadManager().refreshActiveComponents(this.pConn.getContextName());
} else {
} else if (hasAssociatedViewConfigured) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe it is worth to add some comment that we want to skip manual refreshCaseView for picklist-based children (Dropdown, AutoComplete, Checkbox).

const pgRef = this.pConn.getPageReference().replace("caseInfo.content", "");
this.pConn.getActionsApi().refreshCaseView(caseKey, this.viewName, pgRef, refreshOptions);
this.pConn
.getActionsApi()
.refreshCaseView(caseKey, this.viewName, pgRef, refreshOptions)
?.catch((error) => {
console.warn(`${TAG} refreshCaseView failed`, error?.name, error?.message);
});
}

// AutoComplete sets value on event.id whereas Dropdown sets it on event.target.value
const propValue = event?.id || event?.target?.value;
if (propValue && this.canBeChangedInReviewMode && this.isDisplayModeEnabled) {
if (selectionValue && this.canBeChangedInReviewMode && this.isDisplayModeEnabled) {
PCore.getDataApiUtils()
.getCaseEditLock(caseKey, "")
.then((caseResponse) => {
Expand All @@ -317,7 +329,7 @@ export class DataReferenceComponent extends ContainerBaseComponent {
const propArr = this.propName.split(".");
propArr.forEach((element, idx) => {
if (idx + 1 === propArr.length) {
curr[element] = propValue;
curr[element] = selectionValue;
} else {
curr[element] = {};
curr = curr[element];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { BaseComponent } from "../base.component.js";

export class SemanticLinkComponent extends BaseComponent {
jsComponentPConnectData = {};

props = {
value: "",
label: "",
visible: true,
};

init() {
this.jsComponentPConnectData = this.jsComponentPConnect.registerAndSubscribeComponent(
this,
this.checkAndUpdate
);
this.componentsManager.onComponentAdded(this);
this.checkAndUpdate();
}

destroy() {
super.destroy();
this.jsComponentPConnectData.unsubscribeFn?.();
this.componentsManager.onComponentRemoved(this);
}

update(pConn) {
if (this.pConn !== pConn) {
this.pConn = pConn;
this.checkAndUpdate();
}
}

checkAndUpdate() {
if (this.jsComponentPConnect.shouldComponentUpdate(this)) {
this.#updateSelf();
}
}

#updateSelf() {
const configProps = this.pConn.resolveConfigProps(this.pConn.getConfigProps());
this.props.label = configProps.label ?? "";
this.props.value = configProps.text ?? configProps.value ?? "";
this.props.visible = this.utils.getBooleanValue(configProps.visibility ?? this.props.visible);
this.componentsManager.onComponentPropsUpdate(this);
}
}
3 changes: 2 additions & 1 deletion scripts/dxcomponents/mappings/sdk-pega-component-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { IntegerComponent } from "../components/fields/integer.component.js";
// import { PercentageComponent } from './_components/field/percentage/percentage.component';
import { PhoneComponent } from "../components/fields/phone.component.js";
import { RadioButtonsComponent } from "../components/fields/radio-buttons.component.js";
// import { SemanticLinkComponent } from './_components/field/semantic-link/semantic-link.component';
import { SemanticLinkComponent } from "../components/fields/semantic-link.component.js";
import { TextAreaComponent } from "../components/fields/text-area.component.js";
// import { TextComponent } from './_components/field/text/text.component';
// import { TextContentComponent } from './_components/field/text-content/text-content.component';
Expand Down Expand Up @@ -219,6 +219,7 @@ const pegaSdkComponentMap = {
// ScalarList: ScalarListComponent,
// SemanticLink: SemanticLinkComponent,
SimpleComboBox: SimpleComboBoxComponent,
SemanticLink: SemanticLinkComponent,
SimpleTable: SimpleTableComponent,
SimpleTableManual: SimpleTableManualComponent,
SimpleTableSelect: SimpleTableSelectComponent,
Expand Down
Loading
Loading