Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 1867824: Fix dynamic form field ordering logic #6329

Merged
merged 1 commit into from Aug 14, 2020

Conversation

TheRealJon
Copy link
Member

@TheRealJon TheRealJon commented Aug 13, 2020

Update form field ordering logic so that behavior matches documentation. Falls back to ordering by descriptor order.
Move some common dynamic form type definitions into types.ts to prevent dependency cycles.

image

cc @tlwu2013

Update form field ordering logic so that behavior matches documentation. Falls back to ordering by descriptor order.
Move some common dynamic form type definitions into types.ts to prevent dependency cycles.
@openshift-ci-robot openshift-ci-robot added bugzilla/severity-medium Referenced Bugzilla bug's severity is medium for the branch this PR is targeting. bugzilla/valid-bug Indicates that a referenced Bugzilla bug is valid for the branch this PR is targeting. labels Aug 13, 2020
@openshift-ci-robot
Copy link
Contributor

@TheRealJon: This pull request references Bugzilla bug 1867824, which is valid. The bug has been moved to the POST state. The bug has been updated to refer to the pull request using the external bug tracker.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target release (4.6.0) matches configured target release for branch (4.6.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, ON_DEV, POST, POST)

In response to this:

Bug 1867824: Fix dynamic form field ordering logic

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@openshift-ci-robot openshift-ci-robot added the component/olm Related to OLM label Aug 13, 2020
@openshift-ci-robot openshift-ci-robot added the component/shared Related to console-shared label Aug 13, 2020
@openshift-ci-robot
Copy link
Contributor

@TheRealJon: This pull request references Bugzilla bug 1867824, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target release (4.6.0) matches configured target release for branch (4.6.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, ON_DEV, POST, POST)

In response to this:

Bug 1867824: Fix dynamic form field ordering logic

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@TheRealJon
Copy link
Member Author

/assign @spadgett

Comment on lines +10 to +29

export type DynamicFormFieldOptionsList = {
label: string;
value: string;
}[];

export type DynamicFormFieldDependency = {
controlFieldPath: string;
controlFieldValue: string;
controlFieldName: string;
};

export type UiSchemaOptionsWithDependency = {
dependency?: DynamicFormFieldDependency;
};

export type DynamicFormSchemaError = {
title: string;
message: string;
};
Copy link
Member Author

Choose a reason for hiding this comment

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

I was having issues with dependency cycles while trying to improve the types for the sort order function in utils, so I moved these reusable types here to prevent future issues.

Copy link
Member

@spadgett spadgett left a comment

Choose a reason for hiding this comment

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

/lgtm

Thanks @TheRealJon

controlFieldName: string;
};

export type UiSchemaOptionsWithDependency = {
Copy link
Member

Choose a reason for hiding this comment

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

nit: console naming conventions would make this capital UI

Suggested change
export type UiSchemaOptionsWithDependency = {
export type UISchemaOptionsWithDependency = {

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Aug 13, 2020
@openshift-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: spadgett, TheRealJon

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci-robot openshift-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Aug 13, 2020
Comment on lines -56 to +65
const { dependency } = getUiOptions(uiSchema ?? {}) as DependencyUIOption; // Type defs for this function are awful
const { dependency } = getUiOptions(uiSchema ?? {}) as UiSchemaOptionsWithDependency; // Type defs for this function are awful
if (dependency) {
setDependencyMet(
dependency.value ===
_.get(formContext.formData ?? {}, ['spec', ...(dependency.path ?? [])], '').toString(),
dependency?.controlFieldValue ===
_.get(
formContext.formData ?? {},
['spec', ...(dependency?.controlFieldPath ?? [])],
'',
).toString(),
Copy link
Member Author

Choose a reason for hiding this comment

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

Updated the uiSchema dependency option to include the control field name (the end of the path) to make sorting easier, and updated property naming to be more descriptive while I was at it.

@@ -1,4 +1,4 @@
export enum SchemaType {
export enum JSONSchemaType {
Copy link
Member Author

Choose a reason for hiding this comment

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

More descriptive name since 'schema' could mean UI schema or JSON schema in the context of the DynamicForm component.

Comment on lines +76 to +143
/**
* Give a property name a sort wieght based on whether it has ui schema, is required, or is a
* control field for a property with a field dependency. A lower weight means higher sort order.
* Fields are weighted according to the following tiers:
* Tier 1 (negative 10^9 - 10^6 magnitude): Required fields with ui schema
* Tier 2 (negative 10^9 magnitude): Required fields without ui schema
* Tier 3 (negative 10^6 magnitude): Optional fields with ui schema
* Tier 4 (positive 10^3 maginitude): Control fields that don't fit any above
* Tier 5 (Infinity): All other fields
*
* Within each of the above tiers, fields are further weighted based on field dependency and ui
* schema defined sort order:
* - Fields without dependency - base weight + ui schema sort order
* - Control field - base weight + ui schema sort order + (nth control field) * 10000
* - Dependent field - control field weight + ui schema sort order + 1
*
* These weight numbers are arbitrary, but spaced far enough apart to prevent collisions.
*/
const getJSONSchemaPropertySortWeight = (
property: string,
jsonSchema: JSONSchema6,
uiSchema: UiSchema,
): number => {
const isRequired = (jsonSchema?.required ?? []).includes(property);
const propertyUISchema = uiSchema?.[property];

// Any sibling has a dependency with this as the control field.
const isControlField = _.some(
uiSchema,
({ 'ui:dependency': dependency }) => dependency?.controlFieldName === property,
);

// Property sort order from ui schema (adjusted to 1-based origin). Use propertyNames.length
// when no uiSchema sortOrder exists. Ensures properties without uiSchema sort order have a
// higher weight than those with.
const propertySortOrder = Number(
propertyUISchema?.['ui:sortOrder'] ?? _.keys(jsonSchema?.properties).length,
);

// This property's control field name, if it exists
const controlFieldName = propertyUISchema?.['ui:dependency']?.controlFieldName;

// A small offset that is added to the base weight so that control fields get sorted
// below other fields in the same 'tier', and allows for depenendt fields to be sorted
// directly after their control field.
const controlFieldOffset = isControlField ? propertySortOrder * THOUSAND : 0;

// Total offset to be added to base tier
const offset = controlFieldOffset + propertySortOrder;

// If this property is a dependent, it's weight is based on it's control field
if (controlFieldName) {
return getJSONSchemaPropertySortWeight(controlFieldName, jsonSchema, uiSchema) + offset + 1;
}

// Tier 1 = -1001000000 (negative one billion one million) + offset
// Tier 2 = -1000000000 (negagive one billion) + offset
// Tier 3 = -1000000 (negative one million) + offset
// Tier 4 = 0 + offset
// Tier 5 = Infinity
return (
// Doesn't meet any sorting criteria, set to infinity
(!isRequired && !propertyUISchema && !controlFieldOffset ? Infinity : 0) -
(isRequired ? BILLION : 0) -
(propertyUISchema ? MILLION : 0) +
offset
);
};
Copy link
Member Author

Choose a reason for hiding this comment

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

Pulled this function out of getJSONSchemaOrder scope.

Copy link
Member Author

Choose a reason for hiding this comment

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

I tried to improve the comments and logic to make this a little bit easier to understand.

Comment on lines +108 to +114
// Property sort order from ui schema (adjusted to 1-based origin). Use propertyNames.length
// when no uiSchema sortOrder exists. Ensures properties without uiSchema sort order have a
// higher weight than those with.
const propertySortOrder = Number(
propertyUISchema?.['ui:sortOrder'] ?? _.keys(jsonSchema?.properties).length,
);

Copy link
Member Author

Choose a reason for hiding this comment

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

This is the main bug fix. I added logic to include the original descriptor index as a sort weight modifier.

Comment on lines -59 to +70
const [, path, value] = capability.match(REGEXP_FIELD_DEPENDENCY_PATH_VALUE) ?? [];
if (!!path && !!value) {
return { 'ui:dependency': { path: descriptorPathToUISchemaPath(path), value } };
}
return {};
const [, path, controlFieldValue] = capability.match(REGEXP_FIELD_DEPENDENCY_PATH_VALUE) ?? [];
const controlFieldPath = descriptorPathToUISchemaPath(path);
const controlFieldName = _.last(controlFieldPath);
return {
...(path &&
controlFieldValue && {
'ui:dependency': {
controlFieldPath,
controlFieldValue,
controlFieldName,
},
}),
Copy link
Member Author

Choose a reason for hiding this comment

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

Update property names to be more descriptive and add control field name for easier reference when sorting dependent/control fields.

@@ -166,6 +175,7 @@ export const descriptorsToUISchema = (
...(description && { 'ui:description': description }),
...(displayName && { 'ui:title': displayName }),
...capabilitiesUISchema,
'ui:sortOrder': index + 1,
Copy link
Member Author

Choose a reason for hiding this comment

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

Add descriptor index to uiSchema to be used in sorting logic.

@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

4 similar comments
@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

@openshift-bot
Copy link
Contributor

/retest

Please review the full test history for this PR and help us cut down flakes.

@openshift-merge-robot openshift-merge-robot merged commit 32f9e95 into openshift:master Aug 14, 2020
@openshift-ci-robot
Copy link
Contributor

@TheRealJon: All pull requests linked via external trackers have merged: openshift/console#6329. Bugzilla bug 1867824 has been moved to the MODIFIED state.

In response to this:

Bug 1867824: Fix dynamic form field ordering logic

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@spadgett spadgett added this to the v4.6 milestone Aug 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. bugzilla/severity-medium Referenced Bugzilla bug's severity is medium for the branch this PR is targeting. bugzilla/valid-bug Indicates that a referenced Bugzilla bug is valid for the branch this PR is targeting. component/olm Related to OLM component/shared Related to console-shared lgtm Indicates that a PR is ready to be merged.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants