Skip to content

Commit 08d3638

Browse files
committed
Some organizing
1 parent 528050a commit 08d3638

5 files changed

Lines changed: 174 additions & 116 deletions

File tree

frontend/packages/portal-frontend/src/geneTea/components/TopTermsTab/FindGenesMatchingTerm/Modal/ExcerptTable.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,16 @@ const ExcerptTable: React.FC<ExcerptTableProps> = ({
3333
// Total number of pages
3434
const totalPages = Math.ceil(allGenesList.length / PAGE_SIZE);
3535

36-
// Determine the full list of genes based on props (local map or API fetch)
37-
const localMatchingGenes = useMemo(
38-
() => termToMatchingGenesMap.get(term) || [],
39-
[termToMatchingGenesMap, term]
40-
);
36+
const matchingGenes = useMemo(() => termToMatchingGenesMap.get(term) || [], [
37+
termToMatchingGenesMap,
38+
term,
39+
]);
4140

4241
// --- 1. Initial Gene List Fetch (Runs once per term) ---
4342
useEffect(() => {
4443
// If not using all genes, the list is already available locally
4544
if (!useAllGenes) {
46-
setAllGenesList(localMatchingGenes);
45+
setAllGenesList(matchingGenes);
4746
setCurrentPage(0);
4847
return;
4948
}
@@ -70,7 +69,7 @@ const ExcerptTable: React.FC<ExcerptTableProps> = ({
7069
setIsLoading(false);
7170
}
7271
})();
73-
}, [term, useAllGenes, localMatchingGenes]);
72+
}, [term, useAllGenes, matchingGenes]);
7473

7574
// --- 2. Excerpt Data Fetch (Runs on term change and page change) ---
7675
useEffect(() => {
@@ -101,7 +100,7 @@ const ExcerptTable: React.FC<ExcerptTableProps> = ({
101100
setIsLoading(false);
102101
}
103102
})();
104-
}, [term, allGenesList, currentPage]); // Depends on term, full list, and current page
103+
}, [term, allGenesList, currentPage]);
105104

106105
// --- Context Creation Handler (Uses the full list) ---
107106
const handleClickCreateTermContext = useCallback(() => {
@@ -131,7 +130,6 @@ const ExcerptTable: React.FC<ExcerptTableProps> = ({
131130

132131
return (
133132
<div className={styles.tableWrapper}>
134-
{" "}
135133
<p className={styles.tableParagraph}>
136134
The term “
137135
<GeneTeaTerm term={term} synonyms={[]} coincident={[]} />” is associated

frontend/packages/portal-frontend/src/geneTea/components/TopTermsTab/FindGenesMatchingTerm/Modal/MatchingTermsModal.tsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,7 @@ function MatchingTermsModal({
3030
// --- 1. SINGLE TERM CONTEXT CREATION ---
3131
const handleClickCreateTermContext = useGeneContextCreation({
3232
name: termOrTermGroup,
33-
terms: useTerms
34-
? [termOrTermGroup]
35-
: [
36-
/* Assuming single selected tab term here if tabs were controlled */
37-
],
33+
terms: useTerms ? [termOrTermGroup] : [],
3834
termToMatchingGenesMap,
3935
useAllGenes,
4036
onComplete: handleContextSaveComplete,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React, { useState, useMemo } from "react";
2+
import Select from "react-select";
3+
import styles from "../../../../../styles/GeneTea.scss";
4+
import ExcerptTable from "../ExcerptTable";
5+
6+
interface LargeTermGroupProps {
7+
termGroup: string;
8+
termsWithinSelectedGroup: string[];
9+
termToMatchingGenesMap: Map<string, string[]>;
10+
useAllGenes: boolean;
11+
}
12+
13+
const LargeTermGroup: React.FC<LargeTermGroupProps> = ({
14+
termGroup,
15+
termsWithinSelectedGroup,
16+
termToMatchingGenesMap,
17+
useAllGenes,
18+
}) => {
19+
const termSelectOptions: { value: string; label: string }[] = useMemo(
20+
() =>
21+
termsWithinSelectedGroup.map((term) => ({
22+
value: term,
23+
label: term,
24+
})),
25+
[termsWithinSelectedGroup]
26+
);
27+
28+
const [selectedTerm, setSelectedTerm] = useState<{
29+
value: string;
30+
label: string;
31+
} | null>(termSelectOptions[0]);
32+
33+
// Mode for > 10 Terms: Show Dropdown and single ExcerptTable
34+
return (
35+
<div className={styles.largeGroupContainer}>
36+
{/* 3. Dropdown (Never Hidden) */}
37+
<h4>
38+
There are {termSelectOptions.length} terms within {termGroup}. Choose a
39+
term to load the gene excerpts.
40+
</h4>
41+
<div className={styles.termSelector}>
42+
<Select
43+
options={termSelectOptions}
44+
value={
45+
selectedTerm
46+
? { value: selectedTerm.value, label: selectedTerm.label }
47+
: null
48+
}
49+
onChange={(selection: any) => {
50+
if (selection) {
51+
setSelectedTerm({
52+
value: selection.value,
53+
label: selection.label,
54+
});
55+
}
56+
}}
57+
placeholder={`Select one of the ${termsWithinSelectedGroup.length} terms...`}
58+
// Ensure the dropdown is always wide enough
59+
styles={{ control: (base) => ({ ...base, minWidth: "300px" }) }}
60+
/>
61+
</div>
62+
<hr />
63+
64+
{/* 4. Excerpt Table for the selected term */}
65+
{selectedTerm && (
66+
<ExcerptTable
67+
key={selectedTerm.value}
68+
useTerms={false}
69+
term={selectedTerm.value} // Use the term from the selected state
70+
termToMatchingGenesMap={termToMatchingGenesMap}
71+
useAllGenes={useAllGenes}
72+
/>
73+
)}
74+
</div>
75+
);
76+
};
77+
78+
export default LargeTermGroup;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import React, { useState, useMemo } from "react";
2+
import styles from "../../../../../styles/GeneTea.scss";
3+
import ExcerptTable from "../ExcerptTable";
4+
import { Tab, Tabs } from "react-bootstrap";
5+
6+
interface SmallTermGroupProps {
7+
termsWithinSelectedGroup: string[];
8+
termToMatchingGenesMap: Map<string, string[]>;
9+
useAllGenes: boolean;
10+
}
11+
12+
const SmallTermGroup: React.FC<SmallTermGroupProps> = ({
13+
termsWithinSelectedGroup,
14+
termToMatchingGenesMap,
15+
useAllGenes,
16+
}) => {
17+
const termSelectOptions: { value: string; label: string }[] = useMemo(
18+
() =>
19+
termsWithinSelectedGroup.map((term) => ({
20+
value: term,
21+
label: term,
22+
})),
23+
[termsWithinSelectedGroup]
24+
);
25+
26+
const [selectedTerm, setSelectedTerm] = useState<{
27+
value: string;
28+
label: string;
29+
} | null>(termSelectOptions[0]);
30+
31+
return (
32+
<>
33+
{selectedTerm && (
34+
<Tabs
35+
className={styles.termGroupTabs}
36+
id="gene_tea_term_group_terms_tabs"
37+
// Ensure the tabs are still controlled, defaulting to the first term
38+
activeKey={selectedTerm.value}
39+
onSelect={(key) => {
40+
// Find the full option object and set it to state for consistency
41+
const selectedOption = termSelectOptions.find(
42+
(opt) => opt.value === key
43+
);
44+
if (selectedOption) {
45+
setSelectedTerm(selectedOption);
46+
}
47+
}}
48+
>
49+
{termsWithinSelectedGroup.map((term) => (
50+
<Tab eventKey={term} title={term} key={term}>
51+
<div className={styles.tabContent}>
52+
{selectedTerm.value === term && (
53+
<ExcerptTable
54+
key={term}
55+
useTerms={false}
56+
term={term}
57+
termToMatchingGenesMap={termToMatchingGenesMap}
58+
useAllGenes={useAllGenes}
59+
/>
60+
)}
61+
</div>
62+
</Tab>
63+
))}
64+
</Tabs>
65+
)}
66+
</>
67+
);
68+
};
69+
70+
export default SmallTermGroup;

frontend/packages/portal-frontend/src/geneTea/components/TopTermsTab/FindGenesMatchingTerm/Modal/TermGroupTabs.tsx

Lines changed: 18 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import React, { useState, useMemo } from "react";
2-
import { Tab, Tabs } from "react-bootstrap";
3-
import Select from "react-select";
4-
import styles from "../../../../styles/GeneTea.scss";
5-
import ExcerptTable from "./ExcerptTable";
1+
import React from "react";
2+
import LargeTermGroup from "./TabTypes/LargeTermGroup";
3+
import SmallTermGroup from "./TabTypes/SmallTermGroup";
64

7-
const TERM_THRESHOLD = 10;
5+
const TERM_THRESHOLD = 2;
86

97
interface TermGroupTabsProps {
108
termGroup: string;
@@ -19,107 +17,25 @@ const TermGroupTabs: React.FC<TermGroupTabsProps> = ({
1917
termToMatchingGenesMap,
2018
useAllGenes,
2119
}) => {
22-
const isLargeGroup = termsWithinSelectedGroup.length > TERM_THRESHOLD;
20+
const isLargeTermGroup = termsWithinSelectedGroup.length > TERM_THRESHOLD;
2321

24-
const termSelectOptions: { value: string; label: string }[] = useMemo(
25-
() =>
26-
termsWithinSelectedGroup.map((term) => ({
27-
value: term,
28-
label: term,
29-
})),
30-
[termsWithinSelectedGroup]
31-
);
32-
33-
// 2. State to manage the selected term (used in both dropdown and tabs)
34-
// Initialize with the first term in the group
35-
const [selectedTerm, setSelectedTerm] = useState<{
36-
value: string;
37-
label: string;
38-
} | null>(termSelectOptions[0]);
39-
40-
if (isLargeGroup) {
41-
// Mode for > 10 Terms: Show Dropdown and single ExcerptTable
22+
if (isLargeTermGroup) {
4223
return (
43-
<div className={styles.largeGroupContainer}>
44-
{/* 3. Dropdown (Never Hidden) */}
45-
<h4>
46-
There are {termSelectOptions.length} terms within {termGroup}. Choose
47-
a term to load the gene excerpts.
48-
</h4>
49-
<div className={styles.termSelector}>
50-
<Select
51-
options={termSelectOptions}
52-
value={
53-
selectedTerm
54-
? { value: selectedTerm.value, label: selectedTerm.label }
55-
: null
56-
}
57-
onChange={(selection: any) => {
58-
if (selection) {
59-
setSelectedTerm({
60-
value: selection.value,
61-
label: selection.label,
62-
});
63-
}
64-
}}
65-
placeholder={`Select one of the ${termsWithinSelectedGroup.length} terms...`}
66-
// Ensure the dropdown is always wide enough
67-
styles={{ control: (base) => ({ ...base, minWidth: "300px" }) }}
68-
/>
69-
</div>
70-
<hr />
71-
72-
{/* 4. Excerpt Table for the selected term */}
73-
{selectedTerm && (
74-
<ExcerptTable
75-
key={selectedTerm.value}
76-
useTerms={false}
77-
term={selectedTerm.value} // Use the term from the selected state
78-
termToMatchingGenesMap={termToMatchingGenesMap}
79-
useAllGenes={useAllGenes}
80-
/>
81-
)}
82-
</div>
24+
<LargeTermGroup
25+
termGroup={termGroup}
26+
termsWithinSelectedGroup={termsWithinSelectedGroup}
27+
termToMatchingGenesMap={termToMatchingGenesMap}
28+
useAllGenes={useAllGenes}
29+
/>
8330
);
8431
}
85-
// Mode for <= 10 Terms: The Tabs component implicitly manages the active tab key.
86-
32+
// Mode for <= 10 Terms
8733
return (
88-
<>
89-
{selectedTerm && (
90-
<Tabs
91-
className={styles.termGroupTabs}
92-
id="gene_tea_term_group_terms_tabs"
93-
// Ensure the tabs are still controlled, defaulting to the first term
94-
activeKey={selectedTerm.value}
95-
onSelect={(key) => {
96-
// Find the full option object and set it to state for consistency
97-
const selectedOption = termSelectOptions.find(
98-
(opt) => opt.value === key
99-
);
100-
if (selectedOption) {
101-
setSelectedTerm(selectedOption);
102-
}
103-
}}
104-
>
105-
{termsWithinSelectedGroup.map((term) => (
106-
<Tab eventKey={term} title={term} key={term}>
107-
<div className={styles.tabContent}>
108-
{selectedTerm.value === term && (
109-
<ExcerptTable
110-
key={term}
111-
useTerms={false}
112-
term={term}
113-
termToMatchingGenesMap={termToMatchingGenesMap}
114-
useAllGenes={useAllGenes}
115-
/>
116-
)}
117-
</div>
118-
</Tab>
119-
))}
120-
</Tabs>
121-
)}
122-
</>
34+
<SmallTermGroup
35+
termsWithinSelectedGroup={termsWithinSelectedGroup}
36+
termToMatchingGenesMap={termToMatchingGenesMap}
37+
useAllGenes={useAllGenes}
38+
/>
12339
);
12440
};
12541

0 commit comments

Comments
 (0)