Skip to content

Commit

Permalink
Merge pull request #193 from microbiomedata/issue-176-slot-any-of-range
Browse files Browse the repository at this point in the history
Check `any_of` on slot definition when determining input type
  • Loading branch information
pkalita-lbl authored Oct 3, 2024
2 parents 6f43e5c + 1e732d6 commit 8d976ea
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 11 deletions.
90 changes: 90 additions & 0 deletions src/components/SampleSlotEditModal/SampleSlotEditModal.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { getSelectState } from "./SampleSlotEditModal";
import { SchemaDefinition } from "../../linkml-metamodel";
import { GoldEcosystemTreeNode, SampleDataValue } from "../../api";

const MOCK_SCHEMA: SchemaDefinition = {
id: "http://example.org/test",
name: "test",
slots: {
a_string: {
name: "a_string",
range: "string",
},
a_choice: {
name: "a_choice",
range: "Choice",
},
a_choice_or_string: {
name: "a_choice_or_string",
any_of: [{ range: "string" }, { range: "Choice" }],
},
},
enums: {
Choice: {
name: "Choice",
permissible_values: {
a: { text: "a" },
b: { text: "b" },
},
},
},
};

const MOCK_GOLD_TREE: GoldEcosystemTreeNode = {
name: "test",
children: [],
};

const MOCK_SAMPLE_DATA: Record<string, SampleDataValue> = {};

const MOCK_SAMPLE_DATA_GETTER = (name: string) => MOCK_SAMPLE_DATA[name];

describe("getSelectState", () => {
it("should return isSelectable = false when slot is null", () => {
const state = getSelectState(
MOCK_SCHEMA,
null,
MOCK_SAMPLE_DATA_GETTER,
MOCK_GOLD_TREE,
);
expect(state.isSelectable).toBe(false);
});

it("should return isSelectable = false when the slot range is string", () => {
const state = getSelectState(
MOCK_SCHEMA,
MOCK_SCHEMA.slots!["a_string"],
MOCK_SAMPLE_DATA_GETTER,
MOCK_GOLD_TREE,
);
expect(state.isSelectable).toBe(false);
});

it("should return isSelectable = true when the slot range is string", () => {
const state = getSelectState(
MOCK_SCHEMA,
MOCK_SCHEMA.slots!["a_choice"],
MOCK_SAMPLE_DATA_GETTER,
MOCK_GOLD_TREE,
);
expect(state.isSelectable).toBe(true);
expect(state.permissibleValues).toEqual({
a: { text: "a" },
b: { text: "b" },
});
});

it("should return isSelectable = true when the slot range is any_of", () => {
const state = getSelectState(
MOCK_SCHEMA,
MOCK_SCHEMA.slots!["a_choice_or_string"],
MOCK_SAMPLE_DATA_GETTER,
MOCK_GOLD_TREE,
);
expect(state.isSelectable).toBe(true);
expect(state.permissibleValues).toEqual({
a: { text: "a" },
b: { text: "b" },
});
});
});
47 changes: 36 additions & 11 deletions src/components/SampleSlotEditModal/SampleSlotEditModal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useMemo, useRef, useState } from "react";
import {
PermissibleValue,
SchemaDefinition,
SlotDefinition,
SlotDefinitionName,
Expand Down Expand Up @@ -60,18 +61,40 @@ function getSelectState(
getSlotValue: (slot: SlotDefinitionName) => SampleDataValue,
goldEcosystemTree: GoldEcosystemTreeNode,
) {
if (
!schema ||
!slot ||
!(schema.enums && slot.range && slot.range in schema.enums)
) {
return {
isSelectable: false,
permissibleValues: {},
warning: "",
};
const nonSelectableState = {
isSelectable: false,
permissibleValues: {} as Record<string, PermissibleValue>,
warning: "",
};
// If the slot is null or the schema doesn't have any enums, don't render a select control.
if (!slot || !schema.enums) {
return nonSelectableState;
}

// If the slot has a range that is an enum, use that. Otherwise, if the slot has an `any_of`
// iterate over those expressions and collect any with enum ranges.
const slotRangeEnumNames: string[] = [];
if (slot.range && slot.range in schema.enums) {
slotRangeEnumNames.push(slot.range);
} else if (slot.any_of !== undefined) {
for (const anyOfExpression of slot.any_of) {
if (anyOfExpression.range && anyOfExpression.range in schema.enums) {
slotRangeEnumNames.push(anyOfExpression.range);
}
}
}

// If we didn't find any enum ranges, don't render a select control.
if (slotRangeEnumNames.length === 0) {
return nonSelectableState;
}
const schemaPermissibleValues: Record<string, PermissibleValue> = {};
for (const enumName of slotRangeEnumNames) {
Object.assign(
schemaPermissibleValues,
schema.enums[enumName].permissible_values,
);
}
const schemaPermissibleValues = schema.enums[slot.range].permissible_values;
let permissibleValues = schemaPermissibleValues || {};
let warning = "";
const goldIndex = GOLD_ECOSYSTEM_SLOTS.indexOf(slot.name);
Expand Down Expand Up @@ -337,3 +360,5 @@ const SampleSlotEditModal: React.FC<SampleSlotEditModalProps> = ({
};

export default SampleSlotEditModal;

export { getSelectState };

0 comments on commit 8d976ea

Please sign in to comment.