implemented pr (worth fixing) feedback

update commit
This commit is contained in:
behrinml
2026-08-06 20:27:25 +02:00
parent 9a397f46e9
commit dd1d40b0d4
56 changed files with 1601 additions and 278 deletions
@@ -36,6 +36,7 @@ export function AddNotificationModal({ provider, onClose }: AddNotificationModal
const [onPrintFailed, setOnPrintFailed] = useState(provider?.on_print_failed ?? true);
const [onPrintStopped, setOnPrintStopped] = useState(provider?.on_print_stopped ?? true);
const [onPrintProgress, setOnPrintProgress] = useState(provider?.on_print_progress ?? false);
const [onBillingChargeFailed, setOnBillingChargeFailed] = useState(provider?.on_billing_charge_failed ?? true);
const [onPrinterOffline, setOnPrinterOffline] = useState(provider?.on_printer_offline ?? false);
const [onPrinterError, setOnPrinterError] = useState(provider?.on_printer_error ?? false);
const [onAiFailureDetection, setOnAiFailureDetection] = useState(provider?.on_ai_failure_detection ?? false);
@@ -192,6 +193,7 @@ export function AddNotificationModal({ provider, onClose }: AddNotificationModal
on_print_failed: onPrintFailed,
on_print_stopped: onPrintStopped,
on_print_progress: onPrintProgress,
on_billing_charge_failed: onBillingChargeFailed,
on_printer_offline: onPrinterOffline,
on_printer_error: onPrinterError,
on_ai_failure_detection: onAiFailureDetection,
@@ -605,6 +607,13 @@ export function AddNotificationModal({ provider, onClose }: AddNotificationModal
</div>
<Toggle checked={onPrintProgress} onChange={setOnPrintProgress} />
</div>
<div className="flex items-center justify-between col-span-2">
<div>
<span className="text-sm text-white">{t('notifications.billingChargeFailedLabel')}</span>
<span className="text-xs text-bambu-gray ml-1">{t('notifications.billingChargeFailedDescription')}</span>
</div>
<Toggle checked={onBillingChargeFailed} onChange={setOnBillingChargeFailed} />
</div>
<div className="flex items-center justify-between col-span-2">
<div>
<span className="text-sm text-white">{t('notifications.plateClearRequired')}</span>
@@ -692,6 +701,7 @@ export function AddNotificationModal({ provider, onClose }: AddNotificationModal
if (onPrintFailed) enabledEvents.push({ key: 'on_print_failed', label: t('notifications.failed') });
if (onPrintStopped) enabledEvents.push({ key: 'on_print_stopped', label: t('notifications.stopped') });
if (onPrintProgress) enabledEvents.push({ key: 'on_print_progress', label: t('notifications.progress') });
if (onBillingChargeFailed) enabledEvents.push({ key: 'on_billing_charge_failed', label: t('notifications.billingChargeFailedLabel') });
if (onPlateClearRequired) enabledEvents.push({ key: 'on_plate_clear_required', label: t('notifications.plateClearRequired') });
if (onBedCooled) enabledEvents.push({ key: 'on_bed_cooled', label: t('notifications.bedCooled') });
if (onFirstLayerComplete) enabledEvents.push({ key: 'on_first_layer_complete', label: t('notifications.firstLayerCompleteLabel') });
@@ -132,6 +132,9 @@ export function NotificationProviderCard({ provider, onEdit }: NotificationProvi
{provider.on_print_stopped && (
<span className="px-2 py-0.5 bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 text-xs rounded">{t('notifications.stopped')}</span>
)}
{provider.on_billing_charge_failed && (
<span className="px-2 py-0.5 bg-red-100 dark:bg-red-600/20 text-red-700 dark:text-red-300 text-xs rounded">{t('notifications.billingChargeFailedLabel')}</span>
)}
{provider.on_print_progress && (
<span className="px-2 py-0.5 bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 text-xs rounded">{t('notifications.progress')}</span>
)}
@@ -354,6 +357,17 @@ export function NotificationProviderCard({ provider, onEdit }: NotificationProvi
/>
</div>
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-white">{t('notifications.billingChargeFailedLabel')}</p>
<p className="text-xs text-bambu-gray">{t('notifications.billingChargeFailedDescription')}</p>
</div>
<Toggle
checked={provider.on_billing_charge_failed ?? true}
onChange={(checked) => updateMutation.mutate({ on_billing_charge_failed: checked })}
/>
</div>
<div className="flex items-center justify-between">
<div>
<p className="text-sm text-white">{t('notifications.progressMilestones')}</p>
@@ -15,6 +15,7 @@ export function CostCenterSelect({
const { t } = useTranslation();
if (costCenters.length === 0) return null;
const selectedCostCenter = costCenters.find((center) => center.id === selectedCostCenterId);
return (
<div className="space-y-1">
@@ -33,6 +34,11 @@ export function CostCenterSelect({
</option>
))}
</select>
{selectedCostCenter?.budget_mode === 'none' && (
<p className="text-xs text-bambu-gray">
{t('printModal.unlimitedNoBudget', 'Unlimited – no budget limit is set.')}
</p>
)}
</div>
);
}
+23 -1
View File
@@ -315,7 +315,7 @@ export function PrintModal({
queryFn: api.getPrinters,
});
const { data: myCostCenters } = useQuery({
const { data: myCostCenters, isLoading: loadingCostCenters } = useQuery({
queryKey: ['finance', 'cost-centers', 'mine'],
queryFn: api.getMyCostCenters,
enabled: !!user && billingEnabled,
@@ -824,6 +824,11 @@ export function PrintModal({
const handleSubmit = async (e?: React.FormEvent, options?: { skipFilamentCheck?: boolean }) => {
e?.preventDefault();
if (billingEnabled && selectedCostCenter == null) {
showToast(t('printModal.noPrintableCostCenters'), 'error');
return;
}
if (
!options?.skipFilamentCheck &&
!settings?.disable_filament_warnings &&
@@ -1277,6 +1282,11 @@ export function PrintModal({
const canSubmit = useMemo(() => {
if (isPending) return false;
// Billing requires a server-authorized cost center. Wait for the query and
// keep submission disabled when the user has no printable center, rather
// than letting the API fail with an unexplained 400.
if (billingEnabled && (loadingCostCenters || selectedCostCenter == null)) return false;
// Need valid printer/model selection
if (assignmentMode === 'printer' && selectedPrinters.length === 0) return false;
// Both are about the single-model case. A cross-model job has no one target
@@ -1313,6 +1323,9 @@ export function PrintModal({
perPlateReqsFailed,
printerStatusLoading,
isCrossModel,
billingEnabled,
loadingCostCenters,
selectedCostCenter,
]);
// Quantity only applies for single-printer or model-based assignment (not multi-printer)
@@ -1714,6 +1727,15 @@ export function PrintModal({
onChange={setSelectedCostCenterId}
/>
)}
{billingEnabled && !loadingCostCenters && printableCostCenters.length === 0 && (
<div
role="alert"
className="p-3 bg-yellow-100 dark:bg-yellow-500/20 border border-yellow-500/50 rounded-lg text-sm text-yellow-800 dark:text-yellow-300 flex items-start gap-2"
>
<AlertTriangle className="w-4 h-4 mt-0.5 shrink-0" />
{t('printModal.noPrintableCostCenters')}
</div>
)}
{/* Quantity — create multiple copies (batch). Hidden for multi-printer
selection, and for multi-plate files where the per-plate steppers