Fixes to NodeJS version.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
Autocomplete,
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
@@ -13,6 +14,7 @@ import {
|
||||
MenuItem,
|
||||
Select,
|
||||
Stack,
|
||||
TextField,
|
||||
Typography
|
||||
} from "@mui/material";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
@@ -84,6 +86,32 @@ const App = () => {
|
||||
[selection, templateFile]
|
||||
);
|
||||
|
||||
const publishers = useMemo(
|
||||
() => [...(publishersQuery.data ?? [])].sort((a, b) => a.localeCompare(b)),
|
||||
[publishersQuery.data]
|
||||
);
|
||||
const offers = useMemo(
|
||||
() => [...(offersQuery.data ?? [])].sort((a, b) => a.localeCompare(b)),
|
||||
[offersQuery.data]
|
||||
);
|
||||
const skus = useMemo(
|
||||
() => [...(skusQuery.data ?? [])].sort((a, b) => a.localeCompare(b)),
|
||||
[skusQuery.data]
|
||||
);
|
||||
const versions = useMemo(
|
||||
() => [...(versionsQuery.data ?? [])].sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" })),
|
||||
[versionsQuery.data]
|
||||
);
|
||||
|
||||
const containsFilter = (options: string[], inputValue: string) => {
|
||||
const query = inputValue.trim().toLowerCase();
|
||||
if (!query) {
|
||||
return options;
|
||||
}
|
||||
|
||||
return options.filter((option) => option.toLowerCase().includes(query));
|
||||
};
|
||||
|
||||
const onRender = async () => {
|
||||
setRenderError("");
|
||||
try {
|
||||
@@ -99,12 +127,13 @@ const App = () => {
|
||||
};
|
||||
|
||||
const loading = locationsQuery.isLoading || templatesQuery.isLoading;
|
||||
const locationsError = locationsQuery.error instanceof Error ? locationsQuery.error.message : "Failed to load locations";
|
||||
|
||||
return (
|
||||
<Box sx={{ minHeight: "100vh", py: 6 }}>
|
||||
<Box sx={{ minHeight: "100vh", py: 4 }}>
|
||||
<Container maxWidth="lg">
|
||||
<Stack spacing={3}>
|
||||
<Typography variant="h3" sx={{ fontWeight: 700 }}>
|
||||
<Typography variant="h4" sx={{ fontWeight: 500 }}>
|
||||
Azure Image Chooser
|
||||
</Typography>
|
||||
<Typography color="text.secondary">
|
||||
@@ -113,6 +142,8 @@ const App = () => {
|
||||
|
||||
{loading ? (
|
||||
<CircularProgress />
|
||||
) : locationsQuery.isError ? (
|
||||
<Alert severity="error">{locationsError}</Alert>
|
||||
) : (
|
||||
<Card>
|
||||
<CardContent>
|
||||
@@ -136,57 +167,36 @@ const App = () => {
|
||||
</Grid>
|
||||
|
||||
<Grid size={{ xs: 12, md: 6 }}>
|
||||
<FormControl fullWidth disabled={!selection.location}>
|
||||
<InputLabel id="publisher-label">Publisher</InputLabel>
|
||||
<Select
|
||||
labelId="publisher-label"
|
||||
label="Publisher"
|
||||
value={selection.publisher}
|
||||
onChange={(event) => setSelection((prev) => ({ ...prev, publisher: event.target.value }))}
|
||||
>
|
||||
{(publishersQuery.data ?? []).map((publisher) => (
|
||||
<MenuItem key={publisher} value={publisher}>
|
||||
{publisher}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Autocomplete
|
||||
options={publishers}
|
||||
value={selection.publisher || null}
|
||||
disabled={!selection.location}
|
||||
onChange={(_event, value) => setSelection((prev) => ({ ...prev, publisher: value ?? "" }))}
|
||||
filterOptions={(options, state) => containsFilter(options, state.inputValue)}
|
||||
renderInput={(params) => <TextField {...params} label="Publisher" />}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid size={{ xs: 12, md: 4 }}>
|
||||
<FormControl fullWidth disabled={!selection.publisher}>
|
||||
<InputLabel id="offer-label">Offer</InputLabel>
|
||||
<Select
|
||||
labelId="offer-label"
|
||||
label="Offer"
|
||||
value={selection.offer}
|
||||
onChange={(event) => setSelection((prev) => ({ ...prev, offer: event.target.value }))}
|
||||
>
|
||||
{(offersQuery.data ?? []).map((offer) => (
|
||||
<MenuItem key={offer} value={offer}>
|
||||
{offer}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Autocomplete
|
||||
options={offers}
|
||||
value={selection.offer || null}
|
||||
disabled={!selection.publisher}
|
||||
onChange={(_event, value) => setSelection((prev) => ({ ...prev, offer: value ?? "" }))}
|
||||
filterOptions={(options, state) => containsFilter(options, state.inputValue)}
|
||||
renderInput={(params) => <TextField {...params} label="Offer" />}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid size={{ xs: 12, md: 4 }}>
|
||||
<FormControl fullWidth disabled={!selection.offer}>
|
||||
<InputLabel id="sku-label">SKU</InputLabel>
|
||||
<Select
|
||||
labelId="sku-label"
|
||||
label="SKU"
|
||||
value={selection.sku}
|
||||
onChange={(event) => setSelection((prev) => ({ ...prev, sku: event.target.value }))}
|
||||
>
|
||||
{(skusQuery.data ?? []).map((sku) => (
|
||||
<MenuItem key={sku} value={sku}>
|
||||
{sku}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Autocomplete
|
||||
options={skus}
|
||||
value={selection.sku || null}
|
||||
disabled={!selection.offer}
|
||||
onChange={(_event, value) => setSelection((prev) => ({ ...prev, sku: value ?? "" }))}
|
||||
filterOptions={(options, state) => containsFilter(options, state.inputValue)}
|
||||
renderInput={(params) => <TextField {...params} label="SKU" />}
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid size={{ xs: 12, md: 4 }}>
|
||||
@@ -198,7 +208,7 @@ const App = () => {
|
||||
value={selection.version}
|
||||
onChange={(event) => setSelection((prev) => ({ ...prev, version: event.target.value }))}
|
||||
>
|
||||
{(versionsQuery.data ?? []).map((version) => (
|
||||
{versions.map((version) => (
|
||||
<MenuItem key={version} value={version}>
|
||||
{version}
|
||||
</MenuItem>
|
||||
@@ -226,7 +236,7 @@ const App = () => {
|
||||
</Grid>
|
||||
|
||||
<Grid size={{ xs: 12, md: 4 }}>
|
||||
<Button fullWidth variant="contained" sx={{ height: "100%" }} onClick={onRender} disabled={!canRender}>
|
||||
<Button fullWidth variant="contained" sx={{ height: "100%" }} color="primary" onClick={onRender} disabled={!canRender}>
|
||||
Generate usage
|
||||
</Button>
|
||||
</Grid>
|
||||
@@ -241,7 +251,10 @@ const App = () => {
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6">Usage snippet</Typography>
|
||||
<Box component="pre" sx={{ overflowX: "auto", p: 2, bgcolor: "#0f172a", color: "#e2e8f0", borderRadius: 2 }}>
|
||||
<Box
|
||||
component="pre"
|
||||
sx={{ overflowX: "auto", p: 2, bgcolor: "grey.100", color: "text.primary", borderRadius: 1, border: 1, borderColor: "divider" }}
|
||||
>
|
||||
{renderedUsage}
|
||||
</Box>
|
||||
</CardContent>
|
||||
@@ -252,7 +265,10 @@ const App = () => {
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6">Available SKUs</Typography>
|
||||
<Box component="pre" sx={{ overflowX: "auto", p: 2, bgcolor: "#111827", color: "#d1fae5", borderRadius: 2 }}>
|
||||
<Box
|
||||
component="pre"
|
||||
sx={{ overflowX: "auto", p: 2, bgcolor: "grey.100", color: "text.primary", borderRadius: 1, border: 1, borderColor: "divider" }}
|
||||
>
|
||||
{skuExport}
|
||||
</Box>
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user