Fixes to NodeJS version.

This commit is contained in:
2026-04-19 20:47:47 +02:00
parent aca4998da7
commit 176fa5ead2
28 changed files with 686 additions and 134 deletions

View File

@@ -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>