chore: upload parte 1 - logica
DevSecOps Enterprise Pipeline / security-gate-and-deploy (push) Failing after 41s

This commit is contained in:
2026-06-01 15:35:53 +01:00
parent a63625d228
commit 9c14a19a87
127 changed files with 22255 additions and 0 deletions
+475
View File
@@ -0,0 +1,475 @@
"use client";
import React from "react"
import { useEffect, useState, useMemo } from "react";
import useSWR from "swr";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Checkbox } from "@/components/ui/checkbox";
import type { Component, Category, Customer, ComponentSpecs } from "@/lib/types";
const fetcher = (url: string) => fetch(url).then((r) => r.json());
// Category-specific specification fields
const CATEGORY_SPECS: Record<string, { key: keyof ComponentSpecs; label: string; type?: string; options?: string[] }[]> = {
resistors: [
{ key: "value", label: "Value" },
{ key: "power", label: "Power" },
{ key: "voltage", label: "Voltage" },
{ key: "tolerance", label: "Tolerance" },
],
capacitors: [
{ key: "value", label: "Value" },
{ key: "power", label: "Power" },
{ key: "voltage", label: "Voltage" },
{ key: "tolerance", label: "Tolerance" },
],
inductors: [
{ key: "value", label: "Value" },
{ key: "tolerance", label: "Tolerance" },
],
leds: [
{ key: "color", label: "Color" },
],
connectors: [
{ key: "no_of_pins", label: "No. of Pins" },
{ key: "no_of_rows", label: "No. of Rows" },
{ key: "connector_type", label: "Type", type: "select", options: ["Female", "Male"] },
],
};
function getCategorySpecKey(categoryName: string | undefined): string | null {
if (!categoryName) return null;
const lower = categoryName.toLowerCase().trim();
// Match plural or singular forms
if (lower.includes("resistor")) return "resistors";
if (lower.includes("capacitor")) return "capacitors";
if (lower.includes("inductor")) return "inductors";
if (lower.includes("led")) return "leds";
if (lower.includes("connector")) return "connectors";
return null;
}
interface ComponentDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
component: Component | null;
categories: Category[];
onSave: (data: Partial<Component>) => Promise<void>;
}
const emptySpecs: ComponentSpecs = {};
export function ComponentDialog({
open,
onOpenChange,
component,
categories,
onSave,
}: ComponentDialogProps) {
const [loading, setLoading] = useState(false);
const { data: customers = [] } = useSWR<Customer[]>("/api/customers", fetcher);
const [form, setForm] = useState({
part_number: "",
name: "",
description: "",
category_id: "",
manufacturer: "",
package_type: "",
unit_price: "",
stock_quantity: "",
min_stock_level: "",
datasheet_url: "",
supplier: "",
supplier_part_number: "",
shelf_location: "",
is_internal: false,
customer_supplied: false,
customer_id: "",
});
const [specs, setSpecs] = useState<ComponentSpecs>({});
// Determine the selected category name for spec fields
const selectedCategoryName = useMemo(() => {
if (!form.category_id) return undefined;
const cat = categories.find((c) => String(c.id) === form.category_id);
return cat?.name;
}, [form.category_id, categories]);
const specKey = getCategorySpecKey(selectedCategoryName);
const specFields = specKey ? CATEGORY_SPECS[specKey] : null;
useEffect(() => {
if (component) {
setForm({
part_number: component.part_number || "",
name: component.name || "",
description: component.description || "",
category_id: component.category_id ? String(component.category_id) : "",
manufacturer: component.manufacturer || "",
package_type: component.package_type || "",
unit_price: String(component.unit_price || ""),
stock_quantity: String(component.stock_quantity || ""),
min_stock_level: String(component.min_stock_level || ""),
datasheet_url: component.datasheet_url || "",
supplier: component.supplier || "",
supplier_part_number: component.supplier_part_number || "",
shelf_location: component.shelf_location || "",
is_internal: component.is_internal ?? false,
customer_supplied: component.customer_supplied ?? false,
customer_id: component.customer_id ? String(component.customer_id) : "",
});
const rawSpecs = component.specs;
setSpecs(typeof rawSpecs === "string" ? JSON.parse(rawSpecs) : rawSpecs || {});
} else {
setForm({
part_number: "",
name: "",
description: "",
category_id: "",
manufacturer: "",
package_type: "",
unit_price: "",
stock_quantity: "",
min_stock_level: "",
datasheet_url: "",
supplier: "",
supplier_part_number: "",
shelf_location: "",
is_internal: false,
customer_supplied: false,
customer_id: "",
});
setSpecs({});
}
}, [component, open]);
function updateSpec(key: keyof ComponentSpecs, value: string) {
setSpecs((prev) => ({ ...prev, [key]: value }));
}
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
try {
await onSave({
...form,
category_id: form.category_id ? Number(form.category_id) : null,
unit_price: Number(form.unit_price) || 0,
stock_quantity: Number(form.stock_quantity) || 0,
min_stock_level: Number(form.min_stock_level) || 0,
is_internal: form.is_internal,
customer_supplied: form.customer_supplied,
customer_id: form.customer_supplied && form.customer_id ? Number(form.customer_id) : null,
specs,
} as unknown as Partial<Component>);
onOpenChange(false);
} finally {
setLoading(false);
}
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>
{component ? "Edit Component" : "Add New Component"}
</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit} className="flex flex-col gap-4 pt-2">
{/* 1. Part Number and Name */}
<div className="grid grid-cols-2 gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="part_number">Part Number *</Label>
<Input
id="part_number"
value={form.part_number}
onChange={(e) => setForm({ ...form, part_number: e.target.value })}
placeholder="e.g. RC0805-10K"
className="font-mono"
required
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="name">Name *</Label>
<Input
id="name"
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
placeholder="e.g. 10K Ohm Resistor"
required
/>
</div>
</div>
{/* 2. Description */}
<div className="flex flex-col gap-2">
<Label htmlFor="description">Description</Label>
<Textarea
id="description"
value={form.description}
onChange={(e) => setForm({ ...form, description: e.target.value })}
placeholder="Component description..."
rows={2}
/>
</div>
{/* 3. Category, Manufacturer, Package */}
<div className="grid grid-cols-3 gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="category">Category</Label>
<Select
value={form.category_id}
onValueChange={(val) => setForm({ ...form, category_id: val })}
>
<SelectTrigger>
<SelectValue placeholder="Select category" />
</SelectTrigger>
<SelectContent>
{categories.map((cat) => (
<SelectItem key={cat.id} value={String(cat.id)}>
{cat.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="manufacturer">Manufacturer</Label>
<Input
id="manufacturer"
value={form.manufacturer}
onChange={(e) => setForm({ ...form, manufacturer: e.target.value })}
placeholder="e.g. Vishay"
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="package_type">Package</Label>
<Input
id="package_type"
value={form.package_type}
onChange={(e) => setForm({ ...form, package_type: e.target.value })}
placeholder="e.g. 0805"
/>
</div>
</div>
{/* 3b. Manufacturer ID (all categories) */}
<div className="flex flex-col gap-2">
<Label htmlFor="manufacturer_id">Manufacturer ID</Label>
<Input
id="manufacturer_id"
value={specs.manufacturer_id || ""}
onChange={(e) => updateSpec("manufacturer_id", e.target.value)}
placeholder="Manufacturer part/ID number"
className="font-mono"
/>
</div>
{/* 4. Category-specific specifications */}
{specFields && specFields.length > 0 && (
<div className="rounded-lg border p-4 flex flex-col gap-3 bg-muted/30">
<p className="text-sm font-medium text-muted-foreground">
{selectedCategoryName} Specifications
</p>
<div className={`grid gap-4 ${specFields.length === 1 ? "grid-cols-1" : specFields.length === 2 ? "grid-cols-2" : specFields.length <= 4 ? "grid-cols-2 sm:grid-cols-4" : "grid-cols-2 sm:grid-cols-3"}`}>
{specFields.map((field) => (
<div key={field.key} className="flex flex-col gap-2">
<Label htmlFor={`spec_${field.key}`} className="text-xs">{field.label}</Label>
{field.type === "select" && field.options ? (
<Select
value={specs[field.key] || ""}
onValueChange={(val) => updateSpec(field.key, val)}
>
<SelectTrigger>
<SelectValue placeholder={`Select ${field.label.toLowerCase()}`} />
</SelectTrigger>
<SelectContent>
{field.options.map((opt) => (
<SelectItem key={opt} value={opt}>{opt}</SelectItem>
))}
</SelectContent>
</Select>
) : (
<Input
id={`spec_${field.key}`}
value={specs[field.key] || ""}
onChange={(e) => updateSpec(field.key, e.target.value)}
placeholder={field.label}
/>
)}
</div>
))}
</div>
</div>
)}
{/* 5. Unit Price, Stock Quantity, Min Stock Level */}
<div className="grid grid-cols-3 gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="unit_price">Unit Price ($)</Label>
<Input
id="unit_price"
type="number"
step="0.0001"
min="0"
value={form.unit_price}
onChange={(e) => setForm({ ...form, unit_price: e.target.value })}
placeholder="0.00"
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="stock_quantity">Stock Quantity</Label>
<Input
id="stock_quantity"
type="number"
min="0"
value={form.stock_quantity}
onChange={(e) => setForm({ ...form, stock_quantity: e.target.value })}
placeholder="0"
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="min_stock_level">Min Stock Level</Label>
<Input
id="min_stock_level"
type="number"
min="0"
value={form.min_stock_level}
onChange={(e) => setForm({ ...form, min_stock_level: e.target.value })}
placeholder="0"
/>
</div>
</div>
{/* 6. Supplier and Supplier Part No */}
<div className="grid grid-cols-2 gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="supplier">Supplier</Label>
<Input
id="supplier"
value={form.supplier}
onChange={(e) => setForm({ ...form, supplier: e.target.value })}
placeholder="e.g. Digi-Key, Mouser"
/>
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="supplier_part_number">Supplier Part No.</Label>
<Input
id="supplier_part_number"
value={form.supplier_part_number}
onChange={(e) => setForm({ ...form, supplier_part_number: e.target.value })}
placeholder="e.g. 311-10KARCT-ND"
className="font-mono"
/>
</div>
</div>
{/* 7. Supplier URL */}
<div className="flex flex-col gap-2">
<Label htmlFor="datasheet_url">Supplier URL</Label>
<Input
id="datasheet_url"
type="url"
value={form.datasheet_url}
onChange={(e) => setForm({ ...form, datasheet_url: e.target.value })}
placeholder="https://..."
/>
</div>
{/* 8. Internal Production and Customer Supplied */}
<div className="grid grid-cols-2 gap-4">
<div className="flex items-center gap-3 rounded-lg border p-3">
<Checkbox
id="is_internal"
checked={form.is_internal}
onCheckedChange={(checked) =>
setForm({ ...form, is_internal: checked === true })
}
/>
<Label htmlFor="is_internal" className="cursor-pointer text-sm font-medium">
Internal Production
</Label>
</div>
<div className="flex items-center gap-3 rounded-lg border p-3">
<Checkbox
id="customer_supplied"
checked={form.customer_supplied}
onCheckedChange={(checked) =>
setForm({ ...form, customer_supplied: checked === true, customer_id: checked ? form.customer_id : "" })
}
/>
<Label htmlFor="customer_supplied" className="cursor-pointer text-sm font-medium">
Customer Supplied
</Label>
</div>
</div>
{form.customer_supplied && (
<div className="flex flex-col gap-2">
<Label htmlFor="customer_id">Supplied by Customer *</Label>
<Select
value={form.customer_id}
onValueChange={(val) => setForm({ ...form, customer_id: val })}
>
<SelectTrigger>
<SelectValue placeholder="Select customer" />
</SelectTrigger>
<SelectContent>
{customers.map((cust) => (
<SelectItem key={cust.id} value={String(cust.id)}>
{cust.code} - {cust.name}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
)}
{/* 9. Shelf / Storage Location */}
<div className="flex flex-col gap-2">
<Label htmlFor="shelf_location">Shelf / Storage Location</Label>
<Input
id="shelf_location"
value={form.shelf_location}
onChange={(e) => setForm({ ...form, shelf_location: e.target.value })}
placeholder="e.g. A3-R2-B5, Rack 1 Shelf 3"
className="font-mono"
/>
</div>
<div className="flex justify-end gap-2 pt-2">
<Button
type="button"
variant="outline"
onClick={() => onOpenChange(false)}
>
Cancel
</Button>
<Button type="submit" disabled={loading}>
{loading ? "Saving..." : component ? "Update" : "Create"}
</Button>
</div>
</form>
</DialogContent>
</Dialog>
);
}