@mytec: iter8.1 ready for test

This commit is contained in:
2026-01-30 14:27:38 +02:00
parent 3fa8185ba9
commit 94cf0f0a07
4 changed files with 34 additions and 10 deletions

View File

@@ -407,6 +407,11 @@ export default function App() {
<option value={600}>600m Smooth</option>
<option value={800}>800m Wide</option>
</select>
{settings.heatmapRadius >= 600 && settings.resolution > 200 && (
<p className="mt-1 text-xs text-amber-600 dark:text-amber-400">
Wide radius works best with 200m resolution. Current: {settings.resolution}m
</p>
)}
</div>
<div>
<label className="text-xs text-gray-500 dark:text-dark-muted">

View File

@@ -154,12 +154,12 @@ export default function SiteList({ onEditSite, onAddSite }: SiteListProps) {
onClick={async (e) => {
e.stopPropagation();
await cloneSector(site.id);
addToast(`Cloned "${site.name}" (+30° azimuth)`, 'success');
addToast(`Added sector to "${site.name}" (+120°)`, 'success');
}}
className="px-2 py-1 text-xs text-purple-600 dark:text-purple-400 hover:bg-purple-50 dark:hover:bg-purple-900/20 rounded min-h-[32px] flex items-center justify-center"
title="Clone sector (+30° azimuth offset)"
title="Add sector at same location (+120° azimuth)"
>
Clone
+ Sector
</button>
<button
onClick={(e) => {

View File

@@ -8,6 +8,7 @@ interface CoverageState {
heatmapVisible: boolean;
setResult: (result: CoverageResult | null) => void;
clearCoverage: () => void;
setIsCalculating: (val: boolean) => void;
updateSettings: (settings: Partial<CoverageSettings>) => void;
toggleHeatmap: () => void;
@@ -27,6 +28,7 @@ export const useCoverageStore = create<CoverageState>((set) => ({
heatmapVisible: true,
setResult: (result) => set({ result }),
clearCoverage: () => set({ result: null }),
setIsCalculating: (val) => set({ isCalculating: val }),
updateSettings: (newSettings) =>
set((state) => ({

View File

@@ -2,6 +2,7 @@ import { create } from 'zustand';
import { v4 as uuidv4 } from 'uuid';
import type { Site, SiteFormData } from '@/types/index.ts';
import { db } from '@/db/schema.ts';
import { useCoverageStore } from '@/store/coverage.ts';
const SITE_COLORS = [
'#ef4444', '#3b82f6', '#22c55e', '#f59e0b', '#8b5cf6',
@@ -106,6 +107,8 @@ export const useSitesStore = create<SitesState>((set, get) => ({
selectedSiteId: state.selectedSiteId === id ? null : state.selectedSiteId,
editingSiteId: state.editingSiteId === id ? null : state.editingSiteId,
}));
// Clear stale coverage data
useCoverageStore.getState().clearCoverage();
},
selectSite: (id: string | null) => set({ selectedSiteId: id }),
@@ -145,29 +148,43 @@ export const useSitesStore = create<SitesState>((set, get) => ({
}
},
// Clone a single sector: duplicate site with 30° azimuth offset
// Clone a single sector: duplicate site at same location with 120° azimuth offset (tri-sector spacing)
cloneSector: async (siteId: string) => {
const source = get().sites.find((s) => s.id === siteId);
if (!source) return;
// Count existing sectors at this location to determine naming
const colocated = get().sites.filter(
(s) => s.lat === source.lat && s.lon === source.lon
);
const sectorLabels = ['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta'];
const sectorIndex = colocated.length; // 0-indexed, next sector
const label = sectorLabels[sectorIndex] ?? `S${sectorIndex + 1}`;
// Base name without any existing sector suffix
const baseName = source.name.replace(/-(Alpha|Beta|Gamma|Delta|Epsilon|Zeta|S\d+|clone)$/i, '');
const addSite = get().addSite;
const newAzimuth = ((source.azimuth ?? 0) + 30) % 360;
const newAzimuth = ((source.azimuth ?? 0) + 120) % 360; // 120° for tri-sector
await addSite({
name: `${source.name}-clone`,
name: `${baseName}-${label}`,
lat: source.lat,
lon: source.lon,
height: source.height,
power: source.power,
gain: source.gain,
gain: source.gain >= 15 ? source.gain : 18, // sector gain default
frequency: source.frequency,
antennaType: source.antennaType,
antennaType: 'sector',
azimuth: newAzimuth,
beamwidth: source.beamwidth,
beamwidth: source.beamwidth ?? 65,
color: '',
visible: true,
notes: source.notes ? `Clone of: ${source.notes}` : `Clone of ${source.name}`,
notes: `Sector ${label} at ${baseName}`,
});
// Clear coverage to force recalculation
useCoverageStore.getState().clearCoverage();
},
// Import sites from parsed data