Skip to content
Draft
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
10 changes: 7 additions & 3 deletions src/components/jsonschemaform/SolaceJsonSchemaForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,21 @@ const hideProperties = (isHidden: any, uiSchema: UiSchema, schema: any) => {
for (const property in properties) {
// hide all errors - errors are displayed with custom widgets
uiSchema[property] = { "ui:hideError": true };

if (isHidden(FormFieldType.property, property, properties[property])) {
// hide rjsf property widget
uiSchema[property]["ui:widget"] = "hidden";
} else if (isHidden(FormFieldType.description, property, properties[property])) {
// hide rjsf property description via custom handling - descriptions are displayed with custom widgets
uiSchema[property]["ui:description"] = CustomProperty.hidden;
}
// Recursively process nested properties
if (properties[property] && typeof properties[property] === "object") {
if (!uiSchema[property]) {
uiSchema[property] = {};
}
hideProperties(isHidden, uiSchema[property], properties[property]);
}
}

hideProperties(isHidden, uiSchema, properties);
} else if (typeof schema === "object") {
for (const property in schema) {
hideProperties(isHidden, uiSchema, schema[property]);
Expand Down
6 changes: 3 additions & 3 deletions storybook/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

217 changes: 212 additions & 5 deletions storybook/src/stories/layout/SolaceJsonSchemaForm.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { expect } from "@storybook/jest";
/*
* Copyright 2023-2025 Solace Systems. All rights reserved.
*
Expand Down Expand Up @@ -26,6 +27,7 @@ import { userEvent, within } from "@storybook/testing-library";
const demoSchema = {
type: "object",
title: "DemoSchema",
description: "added by me",
properties: {
enumProp: {
default: "exclusive",
Expand Down Expand Up @@ -111,6 +113,122 @@ const demoSchema = {
required: ["enumProp", "stringProp", "stringWithPatternProp"]
};

const comprehensiveSchema = {
type: "object",
title: "Comprehensive Form Test",
description: "Tests all hiding scenarios in one schema",
properties: {
// Basic fields from demoSchema
enumProp: {
default: "exclusive",
enum: ["exclusive", "non-exclusive"],
description: "enumProp description",
type: "string"
},
booleanProp: {
default: true,
description: "booleanProp description",
type: "boolean"
},
stringProp: {
default: "#DEAD_MSG_QUEUE",
minLength: 10,
maxLength: 30,
description: "stringProp description",
type: "string"
},
constProp: {
const: "no-access",
description: "constProp description (should be hidden)",
type: "string"
},
longStringProp: {
type: "string",
description: "longStringProp description (should be hidden)",
maxLength: 500
},

// Nested object testing
nestedObject: {
type: "object",
title: "Nested Object",
properties: {
visibleNested: {
type: "string",
title: "Visible Nested",
description: "This nested field should be visible"
},
hiddenNested: {
type: "string",
title: "Hidden Nested",
description: "This nested field should be hidden"
},
deeplyNested: {
type: "object",
title: "Deeply Nested",
properties: {
visibleDeep: {
type: "string",
title: "Visible Deep",
description: "This deeply nested field should be visible"
},
hiddenDeep: {
type: "string",
title: "Hidden Deep",
description: "This deeply nested field should be hidden"
}
}
}
}
},

// AnyOf conditional testing
conditionalSection: {
type: "object",
title: "Conditional Section",
properties: {
conditionalField: {
anyOf: [
{
title: "Option A",
type: "object",
properties: {
optionA: {
type: "string",
title: "Option A Field"
},
hiddenInA: {
type: "string",
title: "Hidden in A"
}
}
},
{
title: "Option B",
type: "object",
properties: {
optionB: {
type: "string",
title: "Option B Field"
},
hiddenInB: {
type: "string",
title: "Hidden in B"
}
}
}
]
},
regularNested: {
type: "string",
title: "Regular Nested Field"
}
}
}
},
required: ["enumProp", "stringProp"]
};

const defaultTransformError = (error) => {
const { name, message } = error;
let newMessage;
Expand Down Expand Up @@ -334,8 +452,8 @@ export const Validation: Story = {
export const Hidden: Story = {
args: {
formItem: {
id: "demoSchema1",
schema: demoSchema
id: "comprehensiveHiding",
schema: comprehensiveSchema
},
formOptions: {
isHidden: (fieldType, propertyName, data) => {
Expand All @@ -345,22 +463,111 @@ export const Hidden: Story = {
case "description":
return true;
case "property":
return data?.const !== undefined || propertyName === "stringLong";
// Hide fields based on property name patterns
return (
data?.const !== undefined ||
propertyName === "longStringProp" ||
propertyName === "hiddenNested" ||
propertyName === "hiddenDeep" ||
propertyName === "hiddenInA" ||
propertyName === "hiddenInB"
);
default:
return false;
}
},
tagName: "div"
},
formData: {
arrayProp: [{ name: "Bob", accessLevel: 50 }],
longPasswordStringProp: "x".repeat(500)
enumProp: "exclusive",
stringProp: "test value",
booleanProp: true,
constProp: "no-access",
longStringProp: "should be hidden",
nestedObject: {
visibleNested: "visible nested value",
hiddenNested: "this should be hidden",
deeplyNested: {
visibleDeep: "visible deep value",
hiddenDeep: "this should also be hidden"
}
},
conditionalSection: {
conditionalField: {
optionA: "option A value",
hiddenInA: "this should be hidden"
},
regularNested: "regular nested value"
}
},
liveValidate: false,
onChange: (data, errors) => action("onChangeHandler")(data, errors),
transformError: defaultTransformError,
transformWidget: defaultTransform,
transformTitle: defaultTransform
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step("Test basic field hiding", async () => {
// Assert visible basic fields are present
expect(canvas.getByText("enumProp")).toBeInTheDocument();
expect(canvas.getByText("stringProp")).toBeInTheDocument();
expect(canvas.getByText("booleanProp")).toBeInTheDocument();

// Assert hidden basic fields are not present
expect(canvas.queryByText("longStringProp")).not.toBeInTheDocument();
expect(canvas.queryByText("constProp")).not.toBeInTheDocument();
});

await step("Test nested field hiding", async () => {
// Assert visible nested fields are present
expect(canvas.getByText("Visible Nested")).toBeInTheDocument();
expect(canvas.getByText("Visible Deep")).toBeInTheDocument();

// Assert hidden nested fields are not present
expect(canvas.queryByText("Hidden Nested")).not.toBeInTheDocument();
expect(canvas.queryByText("Hidden Deep")).not.toBeInTheDocument();
});

await step("Test anyOf conditional hiding - Option A", async () => {
// Assert Option A is initially selected and visible
expect(canvas.getByText("Option A Field")).toBeInTheDocument();
expect(canvas.getByDisplayValue("option A value")).toBeInTheDocument();
expect(canvas.getByText("Regular Nested Field")).toBeInTheDocument();

// Assert hiddenInA field is not present
expect(canvas.queryByText("Hidden in A")).not.toBeInTheDocument();
});

await step("Test anyOf conditional hiding - Option B", async () => {
// Switch to Option B
const dropdown = canvas.getAllByText("Option A");
await userEvent.click(dropdown[0]);

await new Promise((resolve) => setTimeout(resolve, 500));
await userEvent.keyboard("[ArrowDown]");
await userEvent.keyboard("[Enter]");

// Wait for form to update
await new Promise((resolve) => setTimeout(resolve, 100));

// Assert Option B field is now visible
expect(canvas.getByLabelText("Option B Field")).toBeInTheDocument();

// Assert hiddenInB field is not present
expect(canvas.queryByLabelText("Hidden in B")).not.toBeInTheDocument();

// Assert Option A field is no longer visible
expect(canvas.queryByLabelText("Option A Field")).not.toBeInTheDocument();
});

await step("Test form structure integrity", async () => {
// Assert submit button and titles are hidden
expect(canvas.queryByRole("button", { name: "Submit" })).not.toBeInTheDocument();
expect(canvas.queryByText("Comprehensive Form Test")).not.toBeInTheDocument();
expect(canvas.queryByText("Tests all hiding scenarios in one schema")).not.toBeInTheDocument();
});
}
};

Expand Down
Loading