Skip to content

Commit 681ce22

Browse files
committed
add dynamic metadata additions.
1 parent b4b5b46 commit 681ce22

File tree

3 files changed

+129
-22
lines changed

3 files changed

+129
-22
lines changed

src/components/OptimadeClient/DatabaseSelector.jsx

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,58 +3,77 @@ import { getProviderLinks } from "../../api";
33
import debounce from "lodash.debounce";
44
import { slateDropdown } from "../../styles/dropdownStyles";
55

6-
export function DatabaseSelector({ providers, onQueryUrlChange }) {
6+
export function DatabaseSelector({
7+
providers,
8+
onQueryUrlChange,
9+
onChildChange,
10+
}) {
711
const [selectedProvider, setSelectedProvider] = useState("");
812
const [childEntries, setChildEntries] = useState([]);
9-
const [childSelected, setChildSelected] = useState("");
13+
const [childSelected, setChildSelected] = useState(null); // full object
1014
const [customUrl, setCustomUrl] = useState("");
1115
const [loadingChildren, setLoadingChildren] = useState(false);
1216

13-
// 700 ms between no typing before setting url.
1417
const handleCustomChange = debounce((val) => setCustomUrl(val), 700);
1518

1619
useEffect(() => {
17-
if (!selectedProvider || selectedProvider === "__custom__") {
20+
if (!selectedProvider) {
1821
setChildEntries([]);
19-
setChildSelected("");
22+
setChildSelected(null);
23+
onQueryUrlChange("");
24+
onChildChange?.(null);
25+
return;
26+
}
27+
28+
if (selectedProvider === "__custom__") {
29+
setChildEntries([]);
30+
setChildSelected(null);
2031
onQueryUrlChange(customUrl || "");
32+
onChildChange?.(null);
2133
return;
2234
}
2335

2436
async function fetchChildren() {
2537
try {
26-
setLoadingChildren(true); // start loading
38+
setLoadingChildren(true);
2739
const { children } = await getProviderLinks(selectedProvider);
2840
const entries = children.map((c) => c.attributes || {});
2941
setChildEntries(entries);
3042

3143
if (entries.length === 1) {
32-
// Auto-select the only child
33-
setChildSelected(entries[0].base_url);
44+
setChildSelected(entries[0]);
45+
onQueryUrlChange(entries[0].base_url);
46+
onChildChange?.(entries[0]);
3447
} else {
35-
setChildSelected("");
48+
setChildSelected(null);
49+
onQueryUrlChange("");
50+
onChildChange?.(null);
3651
}
3752
} catch (err) {
3853
console.error(err);
3954
setChildEntries([]);
40-
setChildSelected("");
55+
setChildSelected(null);
56+
onQueryUrlChange("");
57+
onChildChange?.(null);
4158
} finally {
42-
setLoadingChildren(false); // stop loading
59+
setLoadingChildren(false);
4360
}
4461
}
4562

4663
fetchChildren();
4764
}, [selectedProvider]);
4865

4966
useEffect(() => {
50-
const url =
51-
selectedProvider === "__custom__"
52-
? customUrl
53-
: childSelected
54-
? childSelected
55-
: "";
56-
onQueryUrlChange(url);
57-
}, [selectedProvider, childSelected, customUrl, onQueryUrlChange]);
67+
if (selectedProvider === "__custom__") {
68+
onQueryUrlChange(customUrl || "");
69+
onChildChange?.(null);
70+
} else if (childSelected) {
71+
onQueryUrlChange(childSelected.base_url);
72+
onChildChange?.(childSelected);
73+
}
74+
}, [customUrl, childSelected, selectedProvider]);
75+
76+
console.log("childSelected", childSelected);
5877

5978
return (
6079
<div className="flex flex-col items-start space-y-2 w-full max-w-md">
@@ -86,9 +105,14 @@ export function DatabaseSelector({ providers, onQueryUrlChange }) {
86105
/>
87106
) : (
88107
<select
89-
className={`${slateDropdown}`}
90-
value={childSelected}
91-
onChange={(e) => setChildSelected(e.target.value)}
108+
className={slateDropdown}
109+
value={childSelected?.base_url || ""}
110+
onChange={(e) => {
111+
const selected = childEntries.find(
112+
(c) => c.base_url === e.target.value
113+
);
114+
setChildSelected(selected || null);
115+
}}
92116
disabled={loadingChildren}
93117
>
94118
{loadingChildren ? (
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const containerclassName =
2+
"items-center justify-center p-4 w-full bg-slate-50 border rounded";
3+
4+
const paragraphclassName = "text-sm px-1";
5+
const headingclassName = "text-lg mb-1";
6+
7+
const hyperlinkclassName = "text-blue-500 hover:underline hover:text-blue-600";
8+
const sectionclassName = "space-y-2";
9+
10+
export default function OptimadeMetadata({ child }) {
11+
if (!child) {
12+
return (
13+
<div className={containerclassName}>
14+
<h3 className={headingclassName}>FAQs</h3>
15+
16+
<section className={sectionclassName}>
17+
<h4 className={headingclassName}>What is the OPTIMADE Client?</h4>
18+
<p className={paragraphclassName}>
19+
This is a friendly client to search through databases and other
20+
implementations exposing an OPTIMADE RESTful API. To get more
21+
information about the OPTIMADE API, please see{" "}
22+
<a
23+
href="https://www.optimade.org/"
24+
target="_blank"
25+
className={hyperlinkclassName}
26+
rel="noopener noreferrer"
27+
>
28+
the official web page
29+
</a>
30+
. All providers are retrieved from{" "}
31+
<a
32+
href="https://providers.optimade.org/"
33+
target="_blank"
34+
className={hyperlinkclassName}
35+
rel="noopener noreferrer"
36+
>
37+
the OPTIMADE consortium's list of providers
38+
</a>
39+
.
40+
</p>
41+
<p className={paragraphclassName}>
42+
To get started, select a provider and subdatabase and start
43+
exploring! This message will be hidden when exploring starts.
44+
</p>
45+
46+
<h4 className={headingclassName}>
47+
Why is a given provider not shown in the client?
48+
</h4>
49+
<p className={paragraphclassName}>
50+
This webapp has filtered some providers for various reasons; some do
51+
not support open queries and others have no link to a meta-database.
52+
Querying should still be possible through the 'Custom endpoint'
53+
method.
54+
</p>
55+
56+
<h4 className={headingclassName}>
57+
Why does the structure visualiser not work for some structures?
58+
</h4>
59+
<p className={paragraphclassName}>
60+
The visualiser is fairly primitive and the OPTIMADE specification is
61+
very broad. For complex structure data (assemblies, unknown
62+
positions, or partial occupancies), the JSON response is still
63+
fetched but the visualisation often fails.
64+
</p>
65+
</section>
66+
</div>
67+
);
68+
}
69+
70+
const { name, description, ...otherAttrs } = child;
71+
72+
return (
73+
<div className={containerclassName}>
74+
<h3 className={headingclassName}>{name}</h3>
75+
{description && <p className={paragraphclassName}>{description}</p>}
76+
</div>
77+
);
78+
}

src/components/OptimadeClient/index.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import { PaginationHandler } from "./PaginationHandler";
1414
import { AnimatePresence, motion } from "framer-motion";
1515

1616
import MaterialsCloudHeader from "mc-react-header";
17+
import OptimadeMetadata from "./OptimadeMetadata";
1718

1819
export function OptimadeClient({ hideProviderList = ["exmpl", "matcloud"] }) {
1920
const [providers, setProviders] = useState([]);
2021
const [queryUrl, setQueryUrl] = useState("");
22+
const [selectedChild, setSelectedChild] = useState(null);
2123
const [currentFilter, setCurrentFilter] = useState("");
2224
const [currentPage, setCurrentPage] = useState(1);
2325
const [currentResult, setCurrentResult] = useState(null);
@@ -97,6 +99,7 @@ export function OptimadeClient({ hideProviderList = ["exmpl", "matcloud"] }) {
9799
<div className="mt-4">
98100
<DatabaseSelector
99101
providers={providers}
102+
onChildChange={setSelectedChild}
100103
onQueryUrlChange={(url) => {
101104
// Only reset filter if provider actually changes
102105
if (url !== queryUrl) {
@@ -122,6 +125,8 @@ export function OptimadeClient({ hideProviderList = ["exmpl", "matcloud"] }) {
122125
</div>
123126
)}
124127

128+
<OptimadeMetadata child={selectedChild} />
129+
125130
<div className="pb-4 px-0.5 w-full">
126131
<ProviderInfo queryUrl={queryUrl} />
127132
</div>

0 commit comments

Comments
 (0)