@mytec: iter8.1 ready for test
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) => ({
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user